Пример #1
0
        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);
        }
Пример #3
0
        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));
        }
Пример #4
0
        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);
        }
Пример #5
0
        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);
        }
Пример #6
0
        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));
        }
Пример #7
0
        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);
        }
Пример #8
0
        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();
        }
Пример #9
0
        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));
        }
Пример #10
0
        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));
                    }
                }
            }
        }