private void BuildShapeFromLengthAngleRepresentationDfs( Vector[] vertices, int currentEdgeIndex, int parentEdgeIndex, Vector parentEdgePoint1, Vector parentEdgePoint2, Func <int, int, double, double> lengthCalculator, Func <int, int, double, double> angleCalculator) { // Determine edge direction and length Vector parentEdgeVec = parentEdgePoint2 - parentEdgePoint1; double length = lengthCalculator(currentEdgeIndex, parentEdgeIndex, parentEdgeVec.Length); double angle = angleCalculator(currentEdgeIndex, parentEdgeIndex, Vector.AngleBetween(new Vector(1, 0), parentEdgeVec)); Vector edgeVec = new Vector(Math.Cos(angle), Math.Sin(angle)) * length; // Choose correct start/end points ShapeEdge currentEdge = this.Structure.Edges[currentEdgeIndex]; ShapeEdge parentEdge = this.Structure.Edges[parentEdgeIndex]; Vector edgePoint1, edgePoint2; if (currentEdge.Index1 == parentEdge.Index1) { edgePoint1 = parentEdgePoint1; edgePoint2 = edgePoint1 + edgeVec; } else if (currentEdge.Index1 == parentEdge.Index2) { edgePoint1 = parentEdgePoint2; edgePoint2 = edgePoint1 + edgeVec; } else if (currentEdge.Index2 == parentEdge.Index1) { edgePoint2 = parentEdgePoint1; edgePoint1 = edgePoint2 - edgeVec; } else { Debug.Assert(currentEdge.Index2 == parentEdge.Index2); edgePoint2 = parentEdgePoint2; edgePoint1 = edgePoint2 - edgeVec; } // Setup vertices (some vertex already was placed, but who cares?) vertices[this.Structure.Edges[currentEdgeIndex].Index1] = edgePoint1; vertices[this.Structure.Edges[currentEdgeIndex].Index2] = edgePoint2; foreach (int childEdgeIndex in this.IterateNeighboringEdgeIndices(currentEdgeIndex)) { if (childEdgeIndex != parentEdgeIndex) { BuildShapeFromLengthAngleRepresentationDfs(vertices, childEdgeIndex, currentEdgeIndex, edgePoint1, edgePoint2, lengthCalculator, angleCalculator); } } }
public override bool Equals(object obj) { if (obj == null || GetType() != obj.GetType()) { return(false); } ShapeEdge objCasted = (ShapeEdge)obj; return(this.Index1 == objCasted.Index1 && this.Index2 == objCasted.Index2); }
public Shape FitMeanShape(int width, int height, Vector rootEdgeDirection) { rootEdgeDirection = rootEdgeDirection.GetNormalized(); // Build tree with a root edge scale Vector[] vertices = new Vector[this.Structure.VertexCount]; vertices[this.Structure.Edges[this.rootEdgeIndex].Index1] = new Vector(0, 0); vertices[this.Structure.Edges[this.rootEdgeIndex].Index2] = rootEdgeDirection * this.RootEdgeMeanLength; foreach (int childEdgeIndex in this.IterateNeighboringEdgeIndices(this.rootEdgeIndex)) { BuildShapeFromLengthAngleRepresentationDfs( vertices, childEdgeIndex, this.rootEdgeIndex, vertices[this.Structure.Edges[this.rootEdgeIndex].Index1], vertices[this.Structure.Edges[this.rootEdgeIndex].Index2], (currentEdge, parentEdge, parentLength) => parentLength / this.GetEdgePairParams(parentEdge, currentEdge).MeanLengthRatio, (currentEdge, parentEdge, parentAngle) => parentAngle + this.GetEdgePairParams(parentEdge, currentEdge).MeanAngle); } // Determine axis-aligned bounding box for the generated shapes Vector min = new Vector(Double.PositiveInfinity, Double.PositiveInfinity); Vector max = new Vector(Double.NegativeInfinity, Double.NegativeInfinity); for (int i = 0; i < this.Structure.VertexCount; ++i) { min.X = Math.Min(min.X, vertices[i].X); min.Y = Math.Min(min.Y, vertices[i].Y); max.X = Math.Max(max.X, vertices[i].X); max.Y = Math.Max(max.Y, vertices[i].Y); } Vector center = 0.5 * (min + max); // Shift vertices to the center of image for (int i = 0; i < this.Structure.VertexCount; ++i) { Vector pos = vertices[i]; pos -= center; pos += new Vector(width * 0.5, height * 0.5); vertices[i] = pos; } // Generate best possible edge widths List <double> edgeWidths = new List <double>(); for (int i = 0; i < this.edgeParams.Count; ++i) { ShapeEdge edge = this.Structure.Edges[i]; double length = (vertices[edge.Index1] - vertices[edge.Index2]).Length; edgeWidths.Add(length * this.edgeParams[i].WidthToEdgeLengthRatio); } return(new Shape(this.Structure, vertices, edgeWidths)); }
private static List <ILengthAngleConstraints> CalculateLengthAngleConstraints(ShapeConstraints shapeConstraints) { List <ILengthAngleConstraints> result = new List <ILengthAngleConstraints>(); for (int i = 0; i < shapeConstraints.ShapeStructure.Edges.Count; ++i) { ShapeEdge edge = shapeConstraints.ShapeStructure.Edges[i]; VertexConstraints vertex1Constraints = shapeConstraints.VertexConstraints[edge.Index1]; VertexConstraints vertex2Constraints = shapeConstraints.VertexConstraints[edge.Index2]; result.Add(BoxSetLengthAngleConstraints.FromVertexConstraints(vertex1Constraints, vertex2Constraints, 1, 16)); } return(result); }
public double CalculateEnergy(Shape shape) { if (shape == null) { throw new ArgumentNullException("shape"); } if (shape.Structure != this.Structure) { throw new ArgumentException("Shape and model have different structures.", "shape"); } double totalEnergy = 0; // Root edge term ShapeEdge rootEdge = this.Structure.Edges[this.rootEdgeIndex]; totalEnergy += this.CalculateRootEdgeEnergyTerm( shape.VertexPositions[rootEdge.Index1], shape.VertexPositions[rootEdge.Index2]); // Unary energy terms) for (int i = 0; i < this.Structure.Edges.Count; ++i) { ShapeEdge edge = this.Structure.Edges[i]; totalEnergy += this.CalculateEdgeWidthEnergyTerm( i, shape.EdgeWidths[i], shape.VertexPositions[edge.Index1], shape.VertexPositions[edge.Index2]); } // Pairwise energy terms foreach (Tuple <int, int> edgePair in this.ConstrainedEdgePairs) { totalEnergy += this.CalculateEdgePairLengthEnergyTerm( edgePair.Item1, edgePair.Item2, shape.GetEdgeVector(edgePair.Item1), shape.GetEdgeVector(edgePair.Item2)); totalEnergy += this.CalculateEdgePairAngleEnergyTerm( edgePair.Item1, edgePair.Item2, shape.GetEdgeVector(edgePair.Item1), shape.GetEdgeVector(edgePair.Item2)); } return(totalEnergy); }
public static ShapeModel Learn(IEnumerable <Shape> shapes) { if (shapes == null) { throw new ArgumentNullException("shapes"); } Shape firstShape = shapes.FirstOrDefault(); Dictionary <int, List <int> > vertexToEdges = new Dictionary <int, List <int> >(); for (int i = 0; i < firstShape.Structure.Edges.Count; ++i) { ShapeEdge edge = firstShape.Structure.Edges[i]; if (!vertexToEdges.ContainsKey(edge.Index1)) { vertexToEdges.Add(edge.Index1, new List <int>()); } vertexToEdges[edge.Index1].Add(i); if (!vertexToEdges.ContainsKey(edge.Index2)) { vertexToEdges.Add(edge.Index2, new List <int>()); } vertexToEdges[edge.Index2].Add(i); } HashSet <Tuple <int, int> > neighboringEdgePairs = new HashSet <Tuple <int, int> >(); foreach (KeyValuePair <int, List <int> > vertexEdgesPair in vertexToEdges) { int startEdge = vertexEdgesPair.Value[0]; for (int otherEdgeIndex = 1; otherEdgeIndex < vertexEdgesPair.Value.Count; ++otherEdgeIndex) { neighboringEdgePairs.Add(new Tuple <int, int>(startEdge, vertexEdgesPair.Value[otherEdgeIndex])); } } return(Learn(shapes, neighboringEdgePairs)); }
public double CalculateBackgroundPenalty(Shape shape, Vector point) { if (shape == null) { throw new ArgumentNullException("shape"); } if (shape.Structure != this.Structure) { throw new ArgumentException("Shape and model have different structures.", "shape"); } double maxPenalty = Double.NegativeInfinity; for (int i = 0; i < this.Structure.Edges.Count; ++i) { ShapeEdge edge = this.Structure.Edges[i]; double penalty = this.CalculateBackgroundPenaltyForEdge( point, shape.EdgeWidths[i], shape.VertexPositions[edge.Index1], shape.VertexPositions[edge.Index2]); maxPenalty = Math.Max(maxPenalty, penalty); } return(maxPenalty); }
private ShapeModel( ShapeStructure structure, IList <ShapeEdgeParams> edgeParams, IDictionary <Tuple <int, int>, ShapeEdgePairParams> edgePairParams, int rootEdgeIndex, double rootEdgeMeanLength, double rootEdgeLengthDeviation) { if (structure == null) { throw new ArgumentNullException("structure"); } if (edgeParams == null) { throw new ArgumentNullException("edgeParams"); } if (edgePairParams == null) { throw new ArgumentNullException("edgePairParams"); } if (rootEdgeMeanLength <= 0) { throw new ArgumentOutOfRangeException("rootEdgeMeanLength", "Parameter value should be positive."); } if (rootEdgeLengthDeviation <= 0) { throw new ArgumentOutOfRangeException("rootEdgeLengthDeviation", "Parameter value should be positive."); } if (edgeParams.Count != structure.Edges.Count) { throw new ArgumentException("Edge params count is not equal to edge count."); } if (rootEdgeIndex < 0 || rootEdgeIndex >= structure.Edges.Count) { throw new ArgumentOutOfRangeException("rootEdgeIndex", "Parameter value should be a valid edge index."); } // Check edge pair constraints foreach (Tuple <int, int> edgePair in edgePairParams.Keys) { if (edgePair.Item1 < 0 || edgePair.Item1 >= structure.Edges.Count || edgePair.Item2 < 0 || edgePair.Item2 >= structure.Edges.Count) { throw new ArgumentOutOfRangeException("edgePairParams", "Invalid edge index given."); } if (edgePair.Item1 == edgePair.Item2) { throw new ArgumentException("Edge pair constraint can't be specified for the single edge.", "edgePairParams"); } if (edgePairParams.ContainsKey(new Tuple <int, int>(edgePair.Item2, edgePair.Item1))) { throw new ArgumentException("Duplicate pairwise constraints specified for some pair of edges.", "edgePairParams"); } ShapeEdge edge1 = structure.Edges[edgePair.Item1]; ShapeEdge edge2 = structure.Edges[edgePair.Item2]; if (edge1.Index1 != edge2.Index1 && edge1.Index2 != edge2.Index1 && edge1.Index1 != edge2.Index2 && edge1.Index2 != edge2.Index2) { throw new ArgumentException("Constrained edge pairs should be connected.", "edgePairParams"); } } // Set this.Structure = structure; this.edgeParams = new List <ShapeEdgeParams>(edgeParams); this.edgePairParams = new Dictionary <Tuple <int, int>, ShapeEdgePairParams>(edgePairParams); this.rootEdgeIndex = rootEdgeIndex; this.rootEdgeMeanLength = rootEdgeMeanLength; this.rootEdgeLengthDeviation = rootEdgeLengthDeviation; this.PostInit(); }
public static ShapeModel Learn(IEnumerable <Shape> shapes, IEnumerable <Tuple <int, int> > constrainedEdgePairs) { if (shapes == null) { throw new ArgumentNullException("shapes"); } if (constrainedEdgePairs == null) { throw new ArgumentNullException("constrainedEdgePairs"); } int shapeCount = shapes.Count(); if (shapeCount <= 1) { throw new ArgumentException("Can't learn from less than two shapes.", "shapes"); } ShapeStructure structure = shapes.First().Structure; if (!shapes.All(s => s.Structure == structure)) { throw new ArgumentException("All the shapes should have the same structure.", "shapes"); } // Learn root edge double rootEdgeLengthDeviation = Double.PositiveInfinity; double rootEdgeMeanLength = 0; int rootEdgeIndex = -1; for (int i = 0; i < structure.Edges.Count; ++i) { double lengthSum = 0, lengthSumSqr = 0; foreach (Shape shape in shapes) { double edgeLength = shape.GetEdgeVector(i).Length; lengthSum += edgeLength; lengthSumSqr += edgeLength * edgeLength; } double meanLength = lengthSumSqr / lengthSum; double lengthRatioDiffSqrSum = 0; foreach (Shape shape in shapes) { double edgeLength = shape.GetEdgeVector(i).Length; double lengthRatioDiff = edgeLength / meanLength - 1; lengthRatioDiffSqrSum += lengthRatioDiff * lengthRatioDiff; } double lengthDeviation = Math.Sqrt(lengthRatioDiffSqrSum / shapeCount); if (rootEdgeIndex == -1 || lengthDeviation < rootEdgeLengthDeviation) { rootEdgeLengthDeviation = lengthDeviation; rootEdgeMeanLength = meanLength; rootEdgeIndex = i; } } // Learn edge params List <ShapeEdgeParams> shapeEdgeParams = new List <ShapeEdgeParams>(); for (int i = 0; i < structure.Edges.Count; ++i) { double sum = 0, sumSqr = 0; foreach (Shape shape in shapes) { double edgeLength = shape.GetEdgeVector(i).Length; double ratio = shape.EdgeWidths[i] / edgeLength; sum += ratio; sumSqr += ratio * ratio; } double meanWidthToLengthRatio = sum / shapeCount; double widthToLengthRatioDeviation = Math.Sqrt(sumSqr / shapeCount - meanWidthToLengthRatio * meanWidthToLengthRatio); shapeEdgeParams.Add(new ShapeEdgeParams(meanWidthToLengthRatio, widthToLengthRatioDeviation)); } // Learn edge pair params Dictionary <Tuple <int, int>, ShapeEdgePairParams> shapeEdgePairParams = new Dictionary <Tuple <int, int>, ShapeEdgePairParams>(); foreach (Tuple <int, int> edgePair in constrainedEdgePairs) { if (edgePair.Item1 < 0 || edgePair.Item1 >= structure.Edges.Count || edgePair.Item2 < 0 || edgePair.Item2 >= structure.Edges.Count) { throw new ArgumentOutOfRangeException("constrainedEdgePairs", "Set of constrained edge pairs contains invalid edge index."); } ShapeEdge edge1 = structure.Edges[edgePair.Item1]; ShapeEdge edge2 = structure.Edges[edgePair.Item2]; if (edge1.Index1 != edge2.Index1 && edge1.Index2 != edge2.Index1 && edge1.Index1 != edge2.Index2 && edge1.Index2 != edge2.Index2) { throw new ArgumentException("Constrained edge pairs should be connected.", "constrainedEdgePairs"); } // Learn means double lengthProdSum = 0, lengthSqrSum = 0; double meanAngle = 0; int shapesConsidered = 0; foreach (Shape shape in shapes) { ++shapesConsidered; Vector edge1Vec = shape.GetEdgeVector(edgePair.Item1); Vector edge2Vec = shape.GetEdgeVector(edgePair.Item2); double length1 = edge1Vec.Length; double length2 = edge2Vec.Length; lengthProdSum += length1 * length2; lengthSqrSum += length2 * length2; double angle = Vector.AngleBetween(edge1Vec, edge2Vec); meanAngle = MathHelper.InterpolateAngle(meanAngle, angle, 1.0 / shapesConsidered); } double meanLengthRatio = lengthProdSum / lengthSqrSum; // Learn deviations double angleAbsDiffSqrSum = 0; double lengthDiffSqrSum = 0; foreach (Shape shape in shapes) { Vector edge1Vec = shape.GetEdgeVector(edgePair.Item1); Vector edge2Vec = shape.GetEdgeVector(edgePair.Item2); double length1 = edge1Vec.Length; double length2 = edge2Vec.Length; double lengthDiff = length1 - meanLengthRatio * length2; lengthDiffSqrSum += lengthDiff * lengthDiff; double angle = Vector.AngleBetween(edge1Vec, edge2Vec); double angleDiff = MathHelper.AngleAbsDifference(meanAngle, angle); angleAbsDiffSqrSum += angleDiff * angleDiff; } double lengthDiffDeviation = Math.Sqrt(lengthDiffSqrSum / shapeCount); double angleDeviation = Math.Sqrt(angleAbsDiffSqrSum / shapeCount); if (shapeEdgePairParams.ContainsKey(edgePair) || shapeEdgePairParams.ContainsKey(new Tuple <int, int>(edgePair.Item2, edgePair.Item1))) { throw new ArgumentException("Same pair of edges is constrained more than once.", "constrainedEdgePairs"); } shapeEdgePairParams.Add(edgePair, new ShapeEdgePairParams(meanAngle, meanLengthRatio, angleDeviation, lengthDiffDeviation)); } return(new ShapeModel(structure, shapeEdgeParams, shapeEdgePairParams, rootEdgeIndex, rootEdgeMeanLength, rootEdgeLengthDeviation)); }
public Vector GetEdgeVector(int edgeIndex) { ShapeEdge edge = this.Structure.Edges[edgeIndex]; return(this.VertexPositions[edge.Index2] - this.VertexPositions[edge.Index1]); }
public void CalculateShapeTerms(ShapeModel model, ShapeConstraints constraintsSet, Image2D <ObjectBackgroundTerm> result) { if (model == null) { throw new ArgumentNullException("model"); } if (constraintsSet == null) { throw new ArgumentNullException("constraintsSet"); } if (result == null) { throw new ArgumentNullException("result"); } if (model.Structure != constraintsSet.ShapeStructure) { throw new ArgumentException("Shape model and shape constraints correspond to different shape structures."); } if (model != this.shapeModel || result.Rectangle.Size != this.imageSize) { this.SetTarget(model, result.Rectangle.Size); } for (int x = 0; x < imageSize.Width; ++x) { for (int y = 0; y < imageSize.Height; ++y) { result[x, y] = new ObjectBackgroundTerm(Double.PositiveInfinity, 0); } } for (int edgeIndex = 0; edgeIndex < this.shapeModel.Structure.Edges.Count; ++edgeIndex) { ShapeEdge edge = this.shapeModel.Structure.Edges[edgeIndex]; VertexConstraints vertexConstraints1 = constraintsSet.VertexConstraints[edge.Index1]; VertexConstraints vertexConstraints2 = constraintsSet.VertexConstraints[edge.Index2]; EdgeConstraints edgeConstraints = constraintsSet.EdgeConstraints[edgeIndex]; Image2D <ObjectBackgroundTerm> edgeTerms; EdgeDescription edgeDescription = new EdgeDescription( vertexConstraints1, vertexConstraints2, edgeConstraints); if (!this.cachedEdgeTerms.TryGetValue(edgeDescription, out edgeTerms)) { edgeTerms = this.AllocateImage(); this.cachedEdgeTerms.Add(edgeDescription, edgeTerms); Polygon convexHull = constraintsSet.GetConvexHullForVertexPair(edge.Index1, edge.Index2); Parallel.For( 0, imageSize.Width, x => { for (int y = 0; y < imageSize.Height; ++y) { Vector pointAsVec = new Vector(x, y); double minDistanceSqr, maxDistanceSqr; MinMaxDistanceForEdge( pointAsVec, convexHull, vertexConstraints1, vertexConstraints2, out minDistanceSqr, out maxDistanceSqr); edgeTerms[x, y] = new ObjectBackgroundTerm( this.shapeModel.CalculateObjectPenaltyForEdge( minDistanceSqr, edgeConstraints.MaxWidth), this.shapeModel.CalculateBackgroundPenaltyForEdge( maxDistanceSqr, edgeConstraints.MinWidth)); } }); } for (int x = 0; x < imageSize.Width; ++x) { for (int y = 0; y < imageSize.Height; ++y) { result[x, y] = new ObjectBackgroundTerm( Math.Min(result[x, y].ObjectTerm, edgeTerms[x, y].ObjectTerm), Math.Max(result[x, y].BackgroundTerm, edgeTerms[x, y].BackgroundTerm)); } } } }