/// <summary> /// Get borders of meaning part of image /// </summary> /// <param name="angle">Skew angle of image</param> /// <param name="completedWidth">Width to which the image was completed</param> /// /// <param name="resultWidth">Width of result (deskewed) image</param> /// <param name="resultHeight">Height of result (deskewed) image</param> /// <param name="projectedImage">Projected image</param> /// <param name="originalWidth">Width of original image</param> /// <param name="originalHeight">Height of original image</param> /// <returns>Rectangle which bounds meaning part of image</returns> private static Rectangle GetImageBordersWithoutWhiteSpaces(double angle, int completedWidth, int resultWidth, int resultHeight, KrecImage projectedImage, int originalWidth, int originalHeight) { var smallImage = BitmapProcessor.RotateGrayscaleImage(projectedImage, -angle); // Для скорости, границы обрезки ищем на уменьшенном изображении var smallBinary = BitmapProcessor.BinarizeGrayscaleImage(smallImage); var cutBorders = ImagePartitioner.GetImageWithoutBorders(smallBinary); var k = (double)originalWidth / completedWidth; var preComplementWidth = (int)(originalWidth / k); var preComplementHeight = (int)(originalHeight / k); var scaleRect = GetUnprojectedRectangle(cutBorders, projectionSideWidth, projectionSideWidth, preComplementWidth, preComplementHeight, originalWidth, originalHeight, angle); int scaleXError = resultWidth / projectionSideWidth; //Увеличиваем с учетом погрешности int scaleYError = resultHeight / projectionSideWidth; scaleRect.X = Math.Max(scaleRect.X - scaleXError, 0); scaleRect.Y = Math.Max(scaleRect.Y - scaleYError, 0); scaleRect.Width = Math.Min(scaleRect.Width + scaleXError, resultWidth - scaleRect.X); scaleRect.Height = Math.Min(scaleRect.Height + scaleYError, resultHeight - scaleRect.Y); return(scaleRect); }
/// <summary> /// Get angle to right image orientation (Multiples Pi/2, from -Pi/2 to Pi) /// </summary> /// <param name="image">Deskewed mage which nedd to be oriented</param> /// <returns>Angle to right orientation</returns> public static double GetAngleToRightOrientation(KrecImage image) { var binary = BitmapProcessor.BinarizeGrayscaleImage(image); var result90 = Get90AngleToRightOrientation(binary, image.HorizontalResolution, image.VerticalResolution); bool isCorrect90Oriented = result90.Item1; var lines = result90.Item2.Lines; // Not enough information to perform calculations of rotation angle // All lines contains less than one char inside if (lines.All(line => line.Chars.Length <= 1)) { return(0); } if (!isCorrect90Oriented) { binary = RotateMatrixBy90(binary); } CleanUpBinaryFromNoise(binary, result90.Item2.BadChars); var linesSum = GetBluredBoundingRectsSums(lines.Select(line => line.BoundingRect), binary); double orientSum = 0; for (var i = 0; i < linesSum.Count; ++i) { orientSum += GetLineOrientation(lines[i].BoundingRect, binary, linesSum[i], result90.Item2.MaxCharHeight); } double expectation = orientSum / linesSum.Count; bool isCorrect180Oriented = (Math.Abs(expectation) < 0.011) || orientSum >= 0; //при мат. ожидании меньше 0.011 результаты данной оценки недостоверны, а статистически вероятнее всего изображение ориентировано правильно if (!isCorrect180Oriented && !isCorrect90Oriented) { return(-Math.PI / 2); } if (!isCorrect180Oriented) { return(Math.PI); } if (!isCorrect90Oriented) { return(Math.PI / 2); } return(0); }
/// <summary> /// Initialize processor for grayscale image /// </summary> /// <param name="image">Grayscale image</param> public RectanglesProcessor(KrecImage image) : this(BitmapProcessor.BinarizeGrayscaleImage(image), image.VerticalResolution) { }