private static double CalculateMinUnaryEdgeEnergy(int edgeIndex, ShapeModel model, ShapeConstraints shapeConstraints, double edgeLength) { double bestWidth = edgeLength * model.GetEdgeParams(edgeIndex).WidthToEdgeLengthRatio; EdgeConstraints edgeConstraints = shapeConstraints.EdgeConstraints[edgeIndex]; bestWidth = MathHelper.Trunc(bestWidth, edgeConstraints.MinWidth, edgeConstraints.MaxWidth); return(model.CalculateEdgeWidthEnergyTerm(edgeIndex, bestWidth, edgeLength)); }
private void SetTarget(ShapeModel newShapeModel, Size newImageSize) { if (newShapeModel.Structure.Edges.Count > CacheCapacity) { throw new InvalidOperationException("Edge count is bigger than cache size. Such shape models are not currently supported."); } this.freeTermImages = new LinkedList <Image2D <ObjectBackgroundTerm> >(); this.cachedEdgeTerms = new LruCache <EdgeDescription, Image2D <ObjectBackgroundTerm> >(CacheCapacity); this.cachedEdgeTerms.CacheItemDiscarded += (sender, args) => this.DeallocateImage(args.DiscardedValue); this.shapeModel = newShapeModel; this.imageSize = newImageSize; }
private static double CalculateSingleEdgeLowerBound( ShapeModel model, ShapeConstraints shapeConstraints, IList<ILengthAngleConstraints> lengthAngleConstraints) { // TODO: support models with multiple edges but without pairwise constraints Debug.Assert(model.Structure.Edges.Count == 1); Debug.Assert(lengthAngleConstraints.Count == 1); double result; // Calculate best possible edge width penalty EdgeConstraints edgeConstraints = shapeConstraints.EdgeConstraints[0]; ShapeEdgeParams edgeParams = model.GetEdgeParams(0); Range lengthBoundary = lengthAngleConstraints[0].LengthBoundary; Range scaledLengthRange = new Range(lengthBoundary.Left * edgeParams.WidthToEdgeLengthRatio, lengthBoundary.Right * edgeParams.WidthToEdgeLengthRatio); Range widthRange = new Range(edgeConstraints.MinWidth, edgeConstraints.MaxWidth); if (scaledLengthRange.IntersectsWith(widthRange)) result = 0; else { result = model.CalculateEdgeWidthEnergyTerm(0, widthRange.Right, lengthBoundary.Left); result = Math.Min(result, model.CalculateEdgeWidthEnergyTerm(0, widthRange.Left, lengthBoundary.Right)); } return result; }
public double CalculateLowerBound(Size imageSize, ShapeModel model, ShapeConstraints shapeConstraints) { if (model == null) throw new ArgumentNullException("model"); if (shapeConstraints == null) throw new ArgumentNullException("shapeConstraints"); if (model.Structure != shapeConstraints.ShapeStructure) throw new ArgumentException("Shape model and shape constraints correspond to different shape structures."); List<ILengthAngleConstraints> lengthAngleConstraints = CalculateLengthAngleConstraints(shapeConstraints); if (model.ConstrainedEdgePairs.Count == 0) { double lowerBound = CalculateSingleEdgeLowerBound(model, shapeConstraints, lengthAngleConstraints); Debug.Assert(lowerBound >= 0); return lowerBound; } // Determine max (scaled) length possible double maxRatio1 = (from edgePair in model.ConstrainedEdgePairs select model.GetEdgePairParams(edgePair.Item1, edgePair.Item2).MeanLengthRatio).Max(); double maxRatio2 = (from edgePair in model.ConstrainedEdgePairs select 1.0 / model.GetEdgePairParams(edgePair.Item1, edgePair.Item2).MeanLengthRatio).Max(); double maxRatio = Math.Max(maxRatio1, maxRatio2); double maxEdgeLength = (new Vector(imageSize.Width, imageSize.Height)).Length; double maxScaledLength = maxEdgeLength * maxRatio; if (maxScaledLength != this.currentMaxScaledLength) { this.currentMaxScaledLength = maxScaledLength; this.transformPool.Clear(); } this.FreeAllDistanceTransforms(); // Calculate distance transforms for all the child edges List<GeneralizedDistanceTransform2D> childTransforms = new List<GeneralizedDistanceTransform2D>(); foreach (int edgeIndex in model.IterateNeighboringEdgeIndices(model.RootEdgeIndex)) childTransforms.Add(CalculateMinEnergiesForAllParentEdges(model, shapeConstraints, model.RootEdgeIndex, edgeIndex, lengthAngleConstraints)); // Find best overall solution double minEnergySum = Double.PositiveInfinity; GeneralizedDistanceTransform2D transform = childTransforms[0]; foreach (int lengthGridIndex in transform.EnumerateInterestGridIndicesX()) { double length = transform.GridIndexToCoordX(lengthGridIndex); double minPairwiseEnergy = Double.PositiveInfinity; foreach (int angleGridIndex in transform.EnumerateInterestGridIndicesY()) { double angle = transform.GridIndexToCoordY(angleGridIndex); const double eps = 1e-8; if (angle > Math.PI + eps || angle < -Math.PI - eps) continue; // Consider only natural angle representations here minPairwiseEnergy = Math.Min(minPairwiseEnergy, CalculateMinPairwiseEdgeEnergy(length, angle, childTransforms)); } double unaryEdgeEnergy = CalculateMinUnaryEdgeEnergy(model.RootEdgeIndex, model, shapeConstraints, length); double rootEdgeEnergy = model.CalculateRootEdgeEnergyTerm(length); minEnergySum = Math.Min(minEnergySum, minPairwiseEnergy + unaryEdgeEnergy + rootEdgeEnergy); } Debug.Assert(minEnergySum >= 0); return minEnergySum; }
private GeneralizedDistanceTransform2D CalculateMinEnergiesForAllParentEdges( ShapeModel model, ShapeConstraints shapeConstraints, int parentEdgeIndex, int currentEdgeIndex, IList<ILengthAngleConstraints> lengthAngleConstraints) { // Calculate child transforms List<GeneralizedDistanceTransform2D> childDistanceTransforms = new List<GeneralizedDistanceTransform2D>(); foreach (int neighborEdgeIndex in model.IterateNeighboringEdgeIndices(currentEdgeIndex)) { // Iterate only through children if (neighborEdgeIndex == parentEdgeIndex) continue; GeneralizedDistanceTransform2D childTransform = CalculateMinEnergiesForAllParentEdges( model, shapeConstraints, currentEdgeIndex, neighborEdgeIndex, lengthAngleConstraints); Debug.Assert(childTransform.IsComputed); childDistanceTransforms.Add(childTransform); } ShapeEdgePairParams pairParams = model.GetEdgePairParams(parentEdgeIndex, currentEdgeIndex); GeneralizedDistanceTransform2D transform = this.AllocateDistanceTransform(); SetupTransformFinitePenaltyRanges(transform, pairParams, lengthAngleConstraints[currentEdgeIndex]); SetupTransformInterestRanges(transform, lengthAngleConstraints[parentEdgeIndex]); Func<double, double, double> penaltyFunction = (scaledLength, shiftedAngle) => { double length = scaledLength / pairParams.MeanLengthRatio; double angle = shiftedAngle + pairParams.MeanAngle; double lengthTolerance = transform.GridStepSizeX / pairParams.MeanLengthRatio; double angleTolerance = transform.GridStepSizeY; if (!lengthAngleConstraints[currentEdgeIndex].InRange(length, lengthTolerance, angle, angleTolerance)) return 1e+20; double penalty = CalculateMinUnaryEdgeEnergy(currentEdgeIndex, model, shapeConstraints, length) + CalculateMinPairwiseEdgeEnergy(length, angle, childDistanceTransforms); return penalty; }; transform.Compute( 0.5 / MathHelper.Sqr(pairParams.LengthDiffDeviation), 0.5 / MathHelper.Sqr(pairParams.AngleDeviation), penaltyFunction); return transform; }
private static double CalculateMinUnaryEdgeEnergy(int edgeIndex, ShapeModel model, ShapeConstraints shapeConstraints, double edgeLength) { double bestWidth = edgeLength * model.GetEdgeParams(edgeIndex).WidthToEdgeLengthRatio; EdgeConstraints edgeConstraints = shapeConstraints.EdgeConstraints[edgeIndex]; bestWidth = MathHelper.Trunc(bestWidth, edgeConstraints.MinWidth, edgeConstraints.MaxWidth); return model.CalculateEdgeWidthEnergyTerm(edgeIndex, bestWidth, edgeLength); }
public Shape MutateShape(Shape shape, ShapeModel shapeModel, Size imageSize, double normalizedTemperature) { if (shape == null) { throw new ArgumentNullException("shape"); } if (shapeModel == null) { throw new ArgumentNullException("shapeModel"); } double maxImageSideSize = Math.Max(imageSize.Width, imageSize.Height); Shape mutatedShape; double weightSum = this.edgeWidthMutationWeight + this.edgeLengthMutationWeight + this.edgeAngleMutationWeight + this.shapeTranslationWeight + this.shapeScaleWeight; if (weightSum <= 0) { throw new InvalidOperationException("At least one type of mutation should have non-zero probability weight."); } double rand = Random.Double(0, weightSum); // Shape part mutation if (rand < this.edgeWidthMutationWeight + this.edgeLengthMutationWeight + this.edgeAngleMutationWeight) { ShapeLengthAngleRepresentation representation = shape.GetLengthAngleRepresentation(); int randomEdge = Random.Int(shape.Structure.Edges.Count); // Mutate edge width if (rand < this.edgeWidthMutationWeight) { double widthShiftStdDev = maxImageSideSize * this.edgeWidthMutationPower * normalizedTemperature; const double minWidth = 3; double widthShift = Random.Normal(0, widthShiftStdDev, -shape.EdgeWidths[randomEdge] + minWidth); representation.EdgeWidths[randomEdge] += widthShift; } // Mutate edge length else if (rand < this.edgeWidthMutationWeight + this.edgeLengthMutationWeight) { double lengthShiftStdDev = maxImageSideSize * this.edgeLengthMutationPower * normalizedTemperature; double lengthShift = Random.Normal(0, lengthShiftStdDev); representation.EdgeLengths[randomEdge] += lengthShift; } // Mutate edge angle else { double angleShiftStdDev = this.edgeAngleMutationPower * normalizedTemperature; double angleShift = Random.Normal(0, angleShiftStdDev); representation.EdgeAngles[randomEdge] += angleShift; } mutatedShape = shapeModel.BuildShapeFromLengthAngleRepresentation(representation); } // Whole shape mutation else { rand -= this.edgeWidthMutationWeight + this.edgeLengthMutationWeight + this.edgeAngleMutationWeight; mutatedShape = shape.Clone(); // Translate shape if (rand < this.shapeTranslationWeight) { Vector maxTopLeftShift = new Vector(Double.NegativeInfinity, Double.NegativeInfinity); Vector minBottomRightShift = new Vector(Double.PositiveInfinity, Double.PositiveInfinity); for (int i = 0; i < mutatedShape.VertexPositions.Count; ++i) { maxTopLeftShift.X = Math.Max(maxTopLeftShift.X, -mutatedShape.VertexPositions[i].X); maxTopLeftShift.Y = Math.Max(maxTopLeftShift.Y, -mutatedShape.VertexPositions[i].Y); minBottomRightShift.X = Math.Min(minBottomRightShift.X, imageSize.Width - mutatedShape.VertexPositions[i].X); minBottomRightShift.Y = Math.Min(minBottomRightShift.Y, imageSize.Height - mutatedShape.VertexPositions[i].Y); } double translationStdDev = maxImageSideSize * this.shapeTranslationPower * normalizedTemperature; Vector shift = new Vector(Random.Normal(0, translationStdDev), Random.Normal(0, translationStdDev)); shift = MathHelper.Trunc(shift, maxTopLeftShift, minBottomRightShift); for (int i = 0; i < mutatedShape.VertexPositions.Count; ++i) { mutatedShape.VertexPositions[i] += shift; } } // Scale shape else { Vector shapeCenter = shape.VertexPositions.Aggregate(Vector.Zero, (a, c) => a + c) / shape.VertexPositions.Count; double scaleStdDev = this.shapeScalePower * normalizedTemperature; const double minScale = 0.1; double scale = Random.Normal(1.0, scaleStdDev, minScale); for (int i = 0; i < mutatedShape.VertexPositions.Count; ++i) { mutatedShape.VertexPositions[i] = shapeCenter + scale * (mutatedShape.VertexPositions[i] - shapeCenter); } } } Debug.Assert(mutatedShape != null); return(mutatedShape); }
private void SetTarget(ShapeModel newShapeModel, Size newImageSize) { if (newShapeModel.Structure.Edges.Count > CacheCapacity) throw new InvalidOperationException("Edge count is bigger than cache size. Such shape models are not currently supported."); this.freeTermImages = new LinkedList<Image2D<ObjectBackgroundTerm>>(); this.cachedEdgeTerms = new LruCache<EdgeDescription, Image2D<ObjectBackgroundTerm>>(CacheCapacity); this.cachedEdgeTerms.CacheItemDiscarded += (sender, args) => this.DeallocateImage(args.DiscardedValue); this.shapeModel = newShapeModel; this.imageSize = newImageSize; }
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)); } }
public Shape MutateShape(Shape shape, ShapeModel shapeModel, Size imageSize, double normalizedTemperature) { if (shape == null) throw new ArgumentNullException("shape"); if (shapeModel == null) throw new ArgumentNullException("shapeModel"); double maxImageSideSize = Math.Max(imageSize.Width, imageSize.Height); Shape mutatedShape; double weightSum = this.edgeWidthMutationWeight + this.edgeLengthMutationWeight + this.edgeAngleMutationWeight + this.shapeTranslationWeight + this.shapeScaleWeight; if (weightSum <= 0) throw new InvalidOperationException("At least one type of mutation should have non-zero probability weight."); double rand = Random.Double(0, weightSum); // Shape part mutation if (rand < this.edgeWidthMutationWeight + this.edgeLengthMutationWeight + this.edgeAngleMutationWeight) { ShapeLengthAngleRepresentation representation = shape.GetLengthAngleRepresentation(); int randomEdge = Random.Int(shape.Structure.Edges.Count); // Mutate edge width if (rand < this.edgeWidthMutationWeight) { double widthShiftStdDev = maxImageSideSize * this.edgeWidthMutationPower * normalizedTemperature; const double minWidth = 3; double widthShift = Random.Normal(0, widthShiftStdDev, -shape.EdgeWidths[randomEdge] + minWidth); representation.EdgeWidths[randomEdge] += widthShift; } // Mutate edge length else if (rand < this.edgeWidthMutationWeight + this.edgeLengthMutationWeight) { double lengthShiftStdDev = maxImageSideSize * this.edgeLengthMutationPower * normalizedTemperature; double lengthShift = Random.Normal(0, lengthShiftStdDev); representation.EdgeLengths[randomEdge] += lengthShift; } // Mutate edge angle else { double angleShiftStdDev = this.edgeAngleMutationPower * normalizedTemperature; double angleShift = Random.Normal(0, angleShiftStdDev); representation.EdgeAngles[randomEdge] += angleShift; } mutatedShape = shapeModel.BuildShapeFromLengthAngleRepresentation(representation); } // Whole shape mutation else { rand -= this.edgeWidthMutationWeight + this.edgeLengthMutationWeight + this.edgeAngleMutationWeight; mutatedShape = shape.Clone(); // Translate shape if (rand < this.shapeTranslationWeight) { Vector maxTopLeftShift = new Vector(Double.NegativeInfinity, Double.NegativeInfinity); Vector minBottomRightShift = new Vector(Double.PositiveInfinity, Double.PositiveInfinity); for (int i = 0; i < mutatedShape.VertexPositions.Count; ++i) { maxTopLeftShift.X = Math.Max(maxTopLeftShift.X, -mutatedShape.VertexPositions[i].X); maxTopLeftShift.Y = Math.Max(maxTopLeftShift.Y, -mutatedShape.VertexPositions[i].Y); minBottomRightShift.X = Math.Min(minBottomRightShift.X, imageSize.Width - mutatedShape.VertexPositions[i].X); minBottomRightShift.Y = Math.Min(minBottomRightShift.Y, imageSize.Height - mutatedShape.VertexPositions[i].Y); } double translationStdDev = maxImageSideSize * this.shapeTranslationPower * normalizedTemperature; Vector shift = new Vector(Random.Normal(0, translationStdDev), Random.Normal(0, translationStdDev)); shift = MathHelper.Trunc(shift, maxTopLeftShift, minBottomRightShift); for (int i = 0; i < mutatedShape.VertexPositions.Count; ++i) mutatedShape.VertexPositions[i] += shift; } // Scale shape else { Vector shapeCenter = shape.VertexPositions.Aggregate(Vector.Zero, (a, c) => a + c) / shape.VertexPositions.Count; double scaleStdDev = this.shapeScalePower * normalizedTemperature; const double minScale = 0.1; double scale = Random.Normal(1.0, scaleStdDev, minScale); for (int i = 0; i < mutatedShape.VertexPositions.Count; ++i) mutatedShape.VertexPositions[i] = shapeCenter + scale * (mutatedShape.VertexPositions[i] - shapeCenter); } } Debug.Assert(mutatedShape != null); return mutatedShape; }
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)); } } } }