public Tuple <TupleList, Image <int, T> > Run <T>( Image <double, T> scaledImage, double scale, double quantizationErrorBound = 2.0, double angleThreshold = 22.5, double detectionThreshold = 0.0, double densityThreshold = 0.7, int numberOfBins = 1024) { var precision = Math.PI * angleThreshold / 180.0; var probabilityOfPointWithAngleWithinPrecision = angleThreshold / 180.0; var gradientMagnitudeThreshold = quantizationErrorBound / Math.Sin(precision); var levelLineResult = _levelLineCalculator.CreateLevelLineImage(scaledImage, gradientMagnitudeThreshold, numberOfBins); var angles = levelLineResult.GradientImage; var modGradientImage = levelLineResult.ModGradientImage; var coordinates = levelLineResult.CoordinatesOrderedByDecreasingGradientMagnitude; var width = angles.Width; var height = angles.Height; var logNumberOfTests = 5.0 * (Math.Log10(width) + Math.Log10(height)) / 2.0 + Math.Log10(11.0); var minimumRegionSize = (int)(-logNumberOfTests / Math.Log10(probabilityOfPointWithAngleWithinPrecision)); var used = new Image <bool, T>(width, height, scaledImage.Metadata); var lineSegments = new TupleList(7); var regionOutput = new Image <int, T>(angles.Width, angles.Height, angles.Metadata); foreach (var coordinate in coordinates) { try { // ReSharper disable once CompareOfFloatsByEqualityOperator if (used[coordinate] || angles[coordinate] == MathHelpers.NoAngle) { continue; } var region = Region <T> .Create(coordinate, angles, modGradientImage, used, precision); if (region.Size < minimumRegionSize) { continue; } var rectangle = region.ToRectangle(probabilityOfPointWithAngleWithinPrecision); // Rectangle must be updated by the refine call if (!region.Refine(densityThreshold, ref rectangle)) { continue; } var logNumberOfFalseAlarms = rectangle.Improve(logNumberOfTests, detectionThreshold); if (logNumberOfFalseAlarms <= detectionThreshold) { continue; } rectangle.FirstPoint.X += 0.5; rectangle.SecondPoint.X += 0.5; rectangle.FirstPoint.Y += 0.5; rectangle.SecondPoint.Y += 0.5; if (!scale.IsRoughlyEqualTo(1)) { rectangle.FirstPoint.X /= scale; rectangle.FirstPoint.Y /= scale; rectangle.SecondPoint.X /= scale; rectangle.SecondPoint.Y /= scale; rectangle.Width /= scale; } lineSegments.AddTuple( rectangle.FirstPoint.X, rectangle.FirstPoint.Y, rectangle.SecondPoint.X, rectangle.SecondPoint.Y, rectangle.Width, rectangle.ProbabilityOfPointWithAngleWithinPrecision, logNumberOfFalseAlarms); // Add the region to the image foreach (var point in region.Points) { // Use the number of line segments so far to identify this // particular line segment. regionOutput[point] = lineSegments.Size; } } catch (Exception e) { Console.WriteLine(e); throw e; } } return(Tuple.Create(lineSegments, regionOutput)); }