public KrecImage ApplyTransformMatrix(KrecImage image, List <Point> corners)
        {
            var matrix        = GetMatrix(corners);
            var width         = image.Width;
            var height        = image.Height;
            var bytesPerPixel = image.Format.BytesPerPixel();
            var result        = new KrecImage(image, new byte[image.ImageData.Length]);

            for (var lineIdx = 0; lineIdx < height; lineIdx++)
            {
                for (int counter = 0, sourceIdx = lineIdx * image.BytesPerLine;
                     counter < width;
                     counter++, sourceIdx += bytesPerPixel)
                {
                    var point = new [, ] {
                        { (double)counter / width, (double)lineIdx / height, 1 }
                    };

                    var color = GetСolor(MultiplyMatrix(point, matrix), image, bytesPerPixel);

                    for (var i = 0; i < bytesPerPixel; i++)
                    {
                        result.ImageData[sourceIdx + i] = color[i];
                    }
                }
            }
            return(result);
        }
        /// <summary>
        /// Calculate deskew angle of bitmap
        /// </summary>
        /// <param name="bmp">Skewed bitmap</param>
        /// <returns>Skew angle</returns>
        public static double CalculateAngle(Bitmap bmp)
        {
            var sourceImage     = KrecImage.FromBitmap(bmp);
            var grayscaledImage = sourceImage.ToGrayscaled();

            return(CalculateAngle(grayscaledImage));
        }
        /// <summary>
        /// Compress image to specified sizes
        /// </summary>
        /// <param name="grayscaleImage">Original image in grayscale</param>
        /// <param name="newWidth">Result width</param>
        /// <param name="newHeight">Result height</param>
        /// <returns>Compressed image</returns>
        public static KrecImage CompressImageToNewSizes(KrecImage grayscaleImage, int newWidth, int newHeight)
        {
            var kx = grayscaleImage.Width / (double)newWidth;
            var ky = grayscaleImage.Height / (double)newHeight;
            var oldBytesPerLine = grayscaleImage.BytesPerLine;
            var newBytesPerLine = KrecImage.CalculateStride(newWidth, grayscaleImage.Format);

            var newImageData = new byte[newHeight * newBytesPerLine];

            for (var newRowIdx = 0; newRowIdx < newHeight; newRowIdx++)
            {
                var oldRowIdx = (int)Math.Round(newRowIdx * ky);
                if (oldRowIdx == grayscaleImage.Height)
                {
                    oldRowIdx--;
                }

                var oldRowStartIdx = oldRowIdx * oldBytesPerLine;
                var newRowStartIdx = newRowIdx * newBytesPerLine;
                for (var newColIdx = 0; newColIdx < newWidth; newColIdx++)
                {
                    var oldColIdx = (int)Math.Round(kx * newColIdx);
                    if (oldColIdx == grayscaleImage.Width)
                    {
                        --oldColIdx;
                    }
                    newImageData[newRowStartIdx + newColIdx] = grayscaleImage.ImageData[oldRowStartIdx + oldColIdx];
                }
            }
            return(new KrecImage(newWidth, newHeight, newBytesPerLine, (float)(grayscaleImage.HorizontalResolution / kx), (float)(grayscaleImage.VerticalResolution / ky), grayscaleImage.Format, newImageData));
        }
示例#4
0
        /// <summary>
        /// Image preparing process. Resizing and fixing quality.
        /// </summary>
        /// <param name="originalImage">Original image</param>
        /// <param name="preComplementWidth">Width used when resizing</param>
        /// <returns>Grayscaled image for descewing</returns>
        private static KrecImage PrepareImageForDeskewing(KrecImage originalImage, out int preComplementWidth)
        {
            if (originalImage.HorizontalResolution > maxDpi)
            {
                // TODO: make k be integer to avoid resampling errors
                double k = maxDpi / originalImage.HorizontalResolution;
                originalImage = ImageSizesModifier.CompressImageToNewSizes(originalImage, (int)Math.Round(originalImage.Width * k),
                                                                           (int)Math.Round(originalImage.Height * k));
            }

            KrecImage projectionImage;

            preComplementWidth = Math.Min(projectionSideWidth, originalImage.Width);
            if (originalImage.Height < maxCompletedSideWith && originalImage.Width < maxCompletedSideWith)             //имитирует поведение прошлого сжимателя
            {
                int    dx              = (maxCompletedSideWith - originalImage.Width) / 2;
                int    dy              = (maxCompletedSideWith - originalImage.Height) / 2;
                int    newWidth        = projectionSideWidth - dx;
                int    newHeight       = projectionSideWidth - dy;
                double k               = Math.Max((double)originalImage.Height / newHeight, (double)originalImage.Width / newWidth);
                var    compressedImage = ImageSizesModifier.CompressImageToNewSizes(originalImage,
                                                                                    (int)(originalImage.Width / k), (int)(originalImage.Height / k));
                compressedImage = BitmapProcessor.AlignImageBackround(compressedImage);

                preComplementWidth = (int)(originalImage.Width / k);
                projectionImage    = ImageSizesModifier.GetImageWithPowerOf2Side(compressedImage, projectionSideWidth);
            }
            else
            {
                var alignedImage = BitmapProcessor.AlignImageBackround(originalImage);
                projectionImage = ImageSizesModifier.GetImageWithPowerOf2Side(alignedImage, projectionSideWidth);
            }

            return(projectionImage);
        }
示例#5
0
        /// <summary>
        /// Print bitmap with array of Boxes in file
        /// </summary>
        /// <param name="boxes">Boxes which will be printed.</param>
        /// <param name="bmp">Bitmap which will be printed.</param>
        /// <param name="outputPath">Path to print bitmap</param>
        /// <param name="minPrintHeight">Minimal height of Boxes which will be printed. Null if doesn't metter.</param>
        /// <param name="maxPrintHeight">Maximal height of Boxes which will be printed. Null if doesn't metter.</param>
        public static void PrintBoxes(IEnumerable <Rectangle> boxes, Bitmap bmp, string outputPath, int?minPrintHeight = null, int?maxPrintHeight = null)
        {
            var image           = KrecImage.FromBitmap(bmp);
            var grayscaledImage = image.ToGrayscaled();

            PrintBoxes(boxes, grayscaledImage, outputPath, maxPrintHeight, maxPrintHeight);
        }
        /// <summary>
        /// Align background of image to white color
        /// </summary>
        /// <param name="image">Image to align background</param>
        /// <returns>Image with aligned bacground</returns>
        public static KrecImage AlignImageBackround(KrecImage image)
        {
            var barGraph   = GetColorsBarGraph(image);
            int threshold  = OtsuThreshold(barGraph);
            int threshold2 = OtsuThreshold(barGraph, 0, threshold);

            var height       = image.Height;
            var width        = image.Width;
            var bytesPerLine = image.BytesPerLine;
            var imageData    = image.ImageData;

            for (var rowIdx = 0; rowIdx < height; rowIdx++)
            {
                var rowStartIdx = rowIdx * bytesPerLine;
                for (var colIdx = 0; colIdx < width; colIdx++)
                {
                    var pixelIdx = rowStartIdx + colIdx;
                    if (imageData[pixelIdx] > threshold2)
                    {
                        imageData[pixelIdx] = 255;
                    }
                }
            }
            return(image);
        }
示例#7
0
        /// <summary>
        /// Find magnitudes of Fourier transfotm and print it in file
        /// </summary>
        /// <param name="image">Square image wich sides size is power of 2</param>
        /// <param name="outputPath">Path to print image</param>
        public static void PrintFourierMagnitudes(KrecImage image, string outputPath)
        {
            int colorsCount = image.Width * image.Height;
            var resultBytes = new byte[image.Width * image.Height];

            var rc = new double[colorsCount];

            for (var i = 0; i < colorsCount; ++i)
            {
                rc[i] = image.ImageData[i] / 255.0;
            }

            rc = SkewAngleDeterminer.FindMagnitudes(rc, image.Width);

            for (var i = 0; i < colorsCount; ++i)
            {
                resultBytes[i] = (byte)Math.Min(255, rc[i] * 10000);
            }

            var krecImage = new KrecImage(
                image.Width, image.Height, image.Width, image.HorizontalResolution, image.VerticalResolution,
                image.Format, resultBytes);

            Print8BppImage(krecImage, outputPath);
        }
示例#8
0
        /// <summary>
        /// Print masked bitmap in file
        /// </summary>
        /// <param name="bmp">Printed bitmap</param>
        /// <param name="mask">Mask (true - will be printed)</param>
        /// <param name="outputPath">Path to print bitmap</param>
        /// <returns></returns>
        public static void PrintMaskedBitmap(Bitmap bmp, bool[,] mask, string outputPath)
        {
            var image           = KrecImage.FromBitmap(bmp);
            var grayscaledImage = image.ToGrayscaled();

            PrintMaskedImage(grayscaledImage, mask, outputPath);
        }
示例#9
0
        public KrecImage Apply(KrecImage image, int radius)
        {
            var width  = image.Width;
            var height = image.Height;
            var result = new KrecImage(image, new byte[image.ImageData.Length]);
            var size   = radius * 2 + 1;

            for (var lineIdx = radius; lineIdx < height - radius; lineIdx++)
            {
                for (var counter = radius; counter < width - radius; counter++)
                {
                    var neighborhood = new List <byte>();
                    for (var i = 0; i < size; i++)
                    {
                        for (var j = 0; j < size; j++)
                        {
                            var y         = lineIdx + i - radius;
                            var sourceIdx = y * image.BytesPerLine + counter;
                            neighborhood.Add(image.ImageData[sourceIdx + j - radius]);
                        }
                    }

                    neighborhood.Sort();
                    var median = neighborhood[neighborhood.Count / 2];
                    result.ImageData[lineIdx * image.BytesPerLine + counter] = median;
                }
            }

            return(result);
        }
示例#10
0
        private const double maxDpi            = 150;  // Images of bigger resolution will be compressed

        /// <summary>
        /// Get skew angle (in radians)
        /// </summary>
        /// <param name="originalBitmap">Bitmap with original image</param>
        /// <returns>Skew angle (in radians)</returns>
        public static double GetSkewAngle(Bitmap originalBitmap)
        {
            var image          = KrecImage.FromBitmap(originalBitmap);
            var grayscaleImage = image.ToGrayscaled(true);

            return(GetSkewAngle(grayscaleImage));
        }
示例#11
0
        /// <summary>
        /// Loads image from file, binarize and rotate it and returns KrecImage
        /// </summary>
        /// <param name="path">Image path</param>
        /// <param name="deskewParameters">The information on how the image has been deskewed</param>
        /// <returns>Binarized and rotated image with deskew parameters</returns>
        public static KrecImage LoadAlignedBinarisedImageFromFile(string path, out DeskewParameters deskewParameters)
        {
            var sourceImage    = KrecImage.FromFile(path);
            var binarizedImage = sourceImage.Binarize();

            deskewParameters = FastImageDeskewer.GetDeskewParameters(binarizedImage);
            return(RotateGrayscaleImage(binarizedImage, deskewParameters.AngleRadians));
        }
 private void Save(KrecImage image, string name)
 {
     if (!debug)
     {
         return;
     }
     image.SaveToFile($"{name}.bmp");
 }
        private KrecImage ReduceImage(Bitmap document)
        {
            var width  = 300;
            var height = width * ((double)document.Height / document.Width);

            dx = (double)document.Width / width;
            dy = document.Height / height;
            return(KrecImage.FromBitmap(new Bitmap(document, width, (int)height)));
        }
        public KrecImage Correct(Bitmap document)
        {
            var normalizeDocument = ReduceImage(document);
            var width             = normalizeDocument.Width;
            var height            = normalizeDocument.Height;

            Save(normalizeDocument, "smallDocument");
            var sw             = Stopwatch.StartNew();
            var binaryDocument = normalizeDocument.Binarize();

            sw.Stop();
            Console.WriteLine($"Binarization, time: {sw.ElapsedMilliseconds} ms");
            Save(binaryDocument, "binaryResult");

            sw = Stopwatch.StartNew();
            var filterDocument = medianFilter.Apply(binaryDocument, 3);

            filterDocument = medianFilter.Apply(filterDocument, 5);
            sw.Stop();
            Console.WriteLine($"Apply median filter, time: {sw.ElapsedMilliseconds} ms");
            Save(filterDocument, "filterResult");

            sw = Stopwatch.StartNew();
            var sobelX = new[, ] {
                { -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 }
            };
            var sobelY = new[, ] {
                { 1, 2, 1 }, { 0, 0, 0 }, { -1, -2, -1 }
            };
            var documentWithBorders = borderSearcher.Search(filterDocument, sobelX, sobelY);

            sw.Stop();
            Console.WriteLine($"Get points of borders, time: {sw.ElapsedMilliseconds} ms");
            Save(documentWithBorders, "bordersResult");

            sw = Stopwatch.StartNew();
            var lines = equationOfLineFinder.GetLines(borderSearcher.GetPoints(), 4, width, height);

            sw.Stop();
            Console.WriteLine($"Find equations of borders: {sw.ElapsedMilliseconds} ms");
            SaveBorders(lines, width, height);

            sw = Stopwatch.StartNew();
            var corners = cornerFinder.FindCorner(lines, width, height);

            corners = corners.Select(c => new Point((int)Math.Round(c.X * dx), (int)Math.Round(c.Y * dy))).ToList();
            sw.Stop();
            Console.WriteLine($"Find corners: {sw.ElapsedMilliseconds} ms");

            sw = Stopwatch.StartNew();
            var correctResult = perspectiveTransformation.ApplyTransformMatrix(KrecImage.FromBitmap(document), corners);

            sw.Stop();
            Console.WriteLine($"Apply transform matrix and smoothing filter: {sw.ElapsedMilliseconds} ms");
            return(correctResult);
        }
示例#15
0
        /// <summary>
        /// Get skew angle (in radians)
        /// </summary>
        /// <param name="originalImage">Original image to process</param>
        /// <returns>Skew angle (in radians)</returns>
        public static double GetSkewAngle(KrecImage originalImage)
        {
            int preComplementWidth;
            var preparedImage = PrepareImageForDeskewing(originalImage, out preComplementWidth);

            double angle      = SkewAngleDeterminer.CalculateAngle(preparedImage);
            double fixedAngle = FixDocumentOrientation(originalImage, preparedImage, angle, preComplementWidth);

            return(fixedAngle);
        }
        /// <summary>
        /// Calculate angle for grayscale image
        /// </summary>
        /// <param name="grayImage">Image in grayscale</param>
        /// <returns>Skew angle</returns>
        public static double CalculateAngle(KrecImage grayImage)
        {
            const double maxError             = 0.01;
            const int    brightestPointsCount = 3000;

            var    brightestPoints = GetBrightestPoints(grayImage, brightestPointsCount);
            double angle           = FindAngleByWideBarGraph(maxError, brightestPoints, grayImage.Width);

            return(CutAngle(angle));
        }
        /// <summary>
        /// Return list of the brightest points after Fourier transform
        /// </summary>
        /// <param name="grayImage">Image to transform</param>
        /// <param name="pointsCount">Count of points</param>
        /// <returns>List of the brightness points</returns>
        public static List <Point> GetBrightestPoints(KrecImage grayImage, int pointsCount)
        {
            var brightestPoints = new List <Point>();
            int pixelsCount     = grayImage.Width * grayImage.Height;

            var height            = grayImage.Height;
            var width             = grayImage.Width;
            var bytesPerLine      = grayImage.BytesPerLine;
            var arrayOfMagnitudes = new double[pixelsCount];
            var targetIdx         = 0;

            for (var rowIdx = 0; rowIdx < height; rowIdx++)
            {
                var rowStartIdx = rowIdx * bytesPerLine;
                for (var colIdx = 0; colIdx < width; colIdx++)
                {
                    arrayOfMagnitudes[targetIdx] = grayImage.ImageData[rowStartIdx + colIdx] / 255.0;
                    targetIdx++;
                }
            }

            arrayOfMagnitudes = FindMagnitudes(arrayOfMagnitudes, grayImage.Width);

            var indexesForNorm = new Tuple <int, double> [pixelsCount];

            for (var i = 0; i < pixelsCount; ++i)
            {
                indexesForNorm[i] = new Tuple <int, double>(i, arrayOfMagnitudes[i]);
            }

            var maxMagnitude = FindKthOrderStatistic(indexesForNorm, pointsCount, true);

            indexesForNorm = indexesForNorm.Skip(pixelsCount - pointsCount).ToArray();

            if (maxMagnitude < 0.00001)
            {
                throw new Exception("Monotone image, can't determine scew angle");
            }

            foreach (var index in indexesForNorm)
            {
                int x = index.Item1 % grayImage.Width;
                int y = index.Item1 / grayImage.Width;

                brightestPoints.Add(new Point(x, y));
            }

            if (brightestPoints.Count == 0)
            {
                throw new Exception("Empty brightest points");
            }

            return(brightestPoints);
        }
示例#18
0
        /// <summary>
        /// Print image with 24bppRgb pixel format
        /// </summary>
        /// <param name="image">Image with 24bppRgb pixel format</param>
        /// <param name="outputPath">Path to print image</param>
        public static void Print24BppImage(KrecImage image, string outputPath)
        {
            var bmp = new Bitmap(image.Width, image.Height, PixelFormat.Format24bppRgb);

            bmp.SetResolution(image.HorizontalResolution, image.VerticalResolution);
            bmp.WithBitmapData(bitmapData =>
            {
                var rgbValues = BitmapProcessor.Reconstruct24To24BppRgbBitmap(bitmapData, image.ImageData);
                IntPtr ptr    = bitmapData.Scan0;
                Marshal.Copy(rgbValues, 0, ptr, rgbValues.Length);
            });
            bmp.Save(outputPath);
        }
示例#19
0
        /// <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);
        }
示例#20
0
        /// <summary>
        /// Print bitmap with array of Boxes in file
        /// </summary>
        /// <param name="boxes">Boxes which will be printed.</param>
        /// <param name="grayscaleImage">Image which will be printed.</param>
        /// <param name="outputPath">Path to print image</param>
        /// <param name="minPrintHeight">Minimal height of Boxes which will be printed. Null if doesn't metter.</param>
        /// <param name="maxPrintHeight">Maximal height of Boxes which will be printed. Null if doesn't metter.</param>
        public static void PrintBoxes(IEnumerable <Rectangle> boxes, KrecImage grayscaleImage, string outputPath, int?minPrintHeight = null, int?maxPrintHeight = null)
        {
            var newWidth        = grayscaleImage.Width;
            var newHeight       = grayscaleImage.Height;
            var oldBytesPerLine = grayscaleImage.BytesPerLine;
            var newBytesPerLine = KrecImage.CalculateStride(newWidth, KrecImagePixelFormat.Format24bppRgb);

            var newImageData = new byte[newBytesPerLine * newHeight * 3];

            for (int rowIdx = 0; rowIdx < newHeight; rowIdx++)
            {
                var oldRowStartIdx = rowIdx * oldBytesPerLine;
                var newRowStartIdx = rowIdx * newBytesPerLine;

                for (int colIdx = 0; colIdx < newWidth; colIdx++)
                {
                    int ix = newRowStartIdx + colIdx * 3;
                    newImageData[ix + 2] = newImageData[ix + 1] = newImageData[ix] = grayscaleImage.ImageData[oldRowStartIdx + colIdx];
                }
            }

            int boxCounter = 0;

            foreach (var box in boxes)
            {
                if ((maxPrintHeight != null && box.Height > maxPrintHeight) || (minPrintHeight != null && box.Height < minPrintHeight))
                {
                    continue;
                }
                for (var i = box.Y; i < box.Y + box.Height && i < grayscaleImage.Height; ++i)
                {
                    for (var j = box.X; j < box.X + box.Width && j < grayscaleImage.Width; ++j)
                    {
                        int pixelIdx = (i * newBytesPerLine + j) * 3;
                        newImageData[pixelIdx]     = 255;
                        newImageData[pixelIdx + 1] = (byte)((boxCounter % 2) * 255);
                        newImageData[pixelIdx + 2] = 0;
                    }
                }
                ++boxCounter;
            }

            var krecImage = new KrecImage(
                newWidth, newHeight, newBytesPerLine,
                grayscaleImage.HorizontalResolution, grayscaleImage.VerticalResolution,
                KrecImagePixelFormat.Format24bppRgb, newImageData);

            Print24BppImage(krecImage, outputPath);
        }
示例#21
0
        /// <summary>
        /// Find magnitudes of Fourier transfotm and print it in file
        /// </summary>
        /// <param name="image">Square image wich sides size is power of 2</param>
        /// <param name="outputPath">Path to print image</param>
        public static void PrintFourierBrightestPoints(KrecImage image, string outputPath)
        {
            var resultBytes     = new byte[image.Width * image.Height];
            var brightestPoints = SkewAngleDeterminer.GetBrightestPoints(image, 3000);

            foreach (var point in brightestPoints)
            {
                resultBytes[point.Y * image.Width + point.X] = 255;
            }

            var krecImage = new KrecImage(
                image.Width, image.Height, image.Width, image.HorizontalResolution, image.VerticalResolution,
                image.Format, resultBytes);

            Print8BppImage(krecImage, outputPath);
        }
示例#22
0
        /// <summary>
        /// Builds integral matrix to claculate sums by given rectangular range
        /// </summary>
        /// <param name="image"></param>
        /// <returns></returns>
        private static uint[,] GetIntegralCopy(KrecImage image)
        {
            var width        = image.Width;
            var height       = image.Height;
            var bytesPerLine = image.BytesPerLine;
            var imageData    = image.ImageData;
            var numArray     = new uint[height + 1, width + 1];

            for (var y = 0; y < height; y++)
            {
                uint lineCurrentSum = 0U;
                for (var x = 0; x < width; x++)
                {
                    lineCurrentSum        += imageData[y * bytesPerLine + x];
                    numArray[y + 1, x + 1] = numArray[y, x + 1] + lineCurrentSum;
                }
            }
            return(numArray);
        }
        /// <summary>
        /// Complete images to power of 2 sizes by white lines. If images width or height more then maxSideWith then compress image.
        /// </summary>
        /// <param name="originalImage">Image to complete</param>
        /// <param name="maxSideWidth">Max completion side width</param>
        /// <returns>Completed image</returns>
        public static KrecImage GetImageWithPowerOf2Side(KrecImage originalImage, int maxSideWidth)
        {
            var newWidth = Math.Max(originalImage.Width, originalImage.Height);

            if ((newWidth & (newWidth - 1)) != 0)             // the fasterst way to check that the number is a power of two
            {
                var exp = (int)Math.Log(newWidth, 2);
                newWidth = (int)Math.Pow(2, exp + 1);
            }

            newWidth = Math.Min(newWidth, maxSideWidth);

            if (newWidth == originalImage.Width && newWidth == originalImage.Height)
            {
                return(originalImage);
            }

            return(GetCompletedToSizeGrayscaleImage(originalImage, newWidth, newWidth));
        }
示例#24
0
        /// <summary>
        /// Convert image to binary format
        /// </summary>
        /// <param name="grayscaleImage">Grayscale image</param>
        /// <returns>0 - white, 1 - black</returns>
        public static bool[,] BinarizeGrayscaleImage(KrecImage grayscaleImage)
        {
            var threshold = OtsuThreshold(grayscaleImage);

            var binary       = new bool[grayscaleImage.Width, grayscaleImage.Height];
            var height       = grayscaleImage.Height;
            var width        = grayscaleImage.Width;
            var bytesPerLine = grayscaleImage.BytesPerLine;
            var imageData    = grayscaleImage.ImageData;

            for (var rowIdx = 0; rowIdx < height; rowIdx++)
            {
                var rowStartIdx = rowIdx * bytesPerLine;
                for (int colIdx = 0; colIdx < width; colIdx++)
                {
                    binary[colIdx, rowIdx] = imageData[rowStartIdx + colIdx] <= threshold;
                }
            }
            return(binary);
        }
示例#25
0
        /// <summary>
        /// Get bar grapgh for colors in greyscale
        /// </summary>
        /// <param name="grayscaledImage">Greyscaled image to process</param>
        /// <returns>Bar graph</returns>
        public static int[] GetColorsBarGraph(KrecImage grayscaledImage)
        {
            var barGraph = new int[256];             //в массиве будет не более 256 элементов

            var width        = grayscaledImage.Width;
            var height       = grayscaledImage.Height;
            var bytesPerLine = grayscaledImage.BytesPerLine;
            var imageData    = grayscaledImage.ImageData;

            for (var rowIdx = 0; rowIdx < height; rowIdx++)
            {
                var rowStartIdx = rowIdx * bytesPerLine;
                for (var colIdx = 0; colIdx < width; colIdx++)
                {
                    barGraph[imageData[rowStartIdx + colIdx]]++;
                }
            }

            return(barGraph);
        }
示例#26
0
        /// <summary>
        /// Print masked bitmap in file
        /// </summary>
        /// <param name="image">Printed image</param>
        /// <param name="mask">Mask (true - will be printed)</param>
        /// <param name="outputPath">Path to print image</param>
        /// <returns></returns>
        public static void PrintMaskedImage(KrecImage image, bool[,] mask, string outputPath)
        {
            var resultBytes = new byte[image.Width * image.Height];

            for (var y = 0; y < image.Height; ++y)
            {
                for (var x = 0; x < image.Width; ++x)
                {
                    if (!mask[x, y])
                    {
                        resultBytes[y * image.BytesPerLine + x] = 255;
                    }
                }
            }

            var krecImage = new KrecImage(
                image.Width, image.Height, image.Width, image.HorizontalResolution, image.VerticalResolution,
                image.Format, resultBytes);

            Print8BppImage(krecImage, outputPath);
        }
        private byte[] GetСolor(double[,] doublePoint, KrecImage image, int bytesPerPixel)
        {
            var doublePointX      = doublePoint[0, 0] / doublePoint[0, 2];
            var doublePointY      = doublePoint[0, 1] / doublePoint[0, 2];
            var neighboringPoints = new []
            {
                new Point((int)Math.Floor(doublePointX), (int)Math.Floor(doublePointY)),
                new Point((int)Math.Floor(doublePointX), (int)Math.Ceiling(doublePointY)),
                new Point((int)Math.Ceiling(doublePointX), (int)Math.Floor(doublePointY)),
                new Point((int)Math.Ceiling(doublePointX), (int)Math.Ceiling(doublePointY))
            };
            var distanceToNeighbors = neighboringPoints.Select(p =>
                                                               Math.Sqrt((doublePointX - p.X) * (doublePointX - p.X) +
                                                                         (doublePointY - p.Y) * (doublePointY - p.Y))).ToArray();
            var sumOfDistances = distanceToNeighbors.Sum();

            var weightNeighbors = new double[4];

            for (var i = 0; i < distanceToNeighbors.Length; i++)
            {
                weightNeighbors[i] = 0.5 - distanceToNeighbors[i] / sumOfDistances;
            }

            var color = new byte[bytesPerPixel];

            for (var pointIndex = 0; pointIndex < neighboringPoints.Length; pointIndex++)
            {
                var neighboringPoint = neighboringPoints[pointIndex];
                if (neighboringPoint.X > 0 && neighboringPoint.X < image.Width && neighboringPoint.Y > 0 && neighboringPoint.Y < image.Height)
                {
                    var index = neighboringPoint.Y * image.BytesPerLine + neighboringPoint.X * bytesPerPixel;
                    for (var i = 0; i < bytesPerPixel; i++)
                    {
                        color[i] += (byte)(image.ImageData[index + i] * weightNeighbors[pointIndex]);
                    }
                }
            }

            return(color);
        }
示例#28
0
        public KrecImage Search(KrecImage image, int[,] maskX, int[,] maskY)
        {
            var width  = image.Width;
            var height = image.Height;
            var result = new KrecImage(image, new byte[image.ImageData.Length]);

            const int limit = 128 * 128;

            for (var lineIdx = 1; lineIdx < height - 1; lineIdx++)
            {
                for (var counter = 1; counter < width - 1; counter++)
                {
                    var gX = 0;
                    var gY = 0;
                    for (var i = 0; i < 3; i++)
                    {
                        var y         = lineIdx + i - 1;
                        var sourceIdx = y * image.BytesPerLine + counter;
                        for (var j = 0; j < 3; j++)
                        {
                            var pixel = image.ImageData[sourceIdx + j - 1];
                            gX += maskX[i, j] * pixel;
                            gY += maskY[i, j] * pixel;
                        }
                    }

                    byte color = 0;
                    if (gX * gX + gY * gY > limit)
                    {
                        color = 255;
                        borderPixels.Add(new Point(counter, lineIdx));
                    }

                    result.ImageData[lineIdx * image.BytesPerLine + counter] = color;
                }
            }
            return(result);
        }
示例#29
0
        /// <summary>
        /// Print image with 8bppIndexed pixel format (before printing convert it to 24bpp)
        /// </summary>
        /// <param name="image">Image with 8bppIndexed pixel format</param>
        /// <param name="outputPath">Path to print image</param>
        public static void Print8BppImage(KrecImage image, string outputPath)
        {
            var bmp = new Bitmap(image.Width, image.Height, PixelFormat.Format24bppRgb);

            bmp.SetResolution(image.HorizontalResolution, image.VerticalResolution);

            int len    = image.Width * image.Height * 3;
            var result = new byte[len];

            for (var i = 0; i < len; i += 3)
            {
                int ind = i / 3;
                result[i] = result[i + 1] = result[i + 2] = image.ImageData[ind];
            }

            bmp.WithBitmapData(bitmapData =>
            {
                var grayscaleValues = BitmapProcessor.Reconstruct24To24BppRgbBitmap(bitmapData, result);
                IntPtr ptr          = bitmapData.Scan0;
                Marshal.Copy(grayscaleValues, 0, ptr, grayscaleValues.Length);
            });
            bmp.Save(outputPath);
        }
示例#30
0
        /// <summary>
        /// Fixing orientiation before returning scew angle
        /// </summary>
        /// <param name="originalImage">Original image</param>
        /// <param name="preparedImage">Prepared for deskewing image</param>
        /// <param name="angle">Calculated scew angle</param>
        /// <param name="preComplementWidth">Width used when resizing</param>
        /// <returns>Fixed descew angle</returns>
        private static double FixDocumentOrientation(KrecImage originalImage, KrecImage preparedImage, double angle, int preComplementWidth)
        {
            var deskewedImage = BitmapProcessor.RotateGrayscaleImage(originalImage, -angle);
            // TODO: бинаризацию можно сделать в этой точке, а не выполнять ее дважды в
            // TODO: GetImageBordersWithoutWhiteSpaces и GetAngleToRightOrientation
            var borders = GetImageBordersWithoutWhiteSpaces(angle, preComplementWidth, deskewedImage.Width, deskewedImage.Height, preparedImage, originalImage.Width, originalImage.Height);

            var imagePart = deskewedImage.GetSubregion(borders);

            var    orientationResult = OrientationDeterminer.GetAngleToRightOrientation(imagePart);
            double orientAngle       = orientationResult;
            double result            = angle - orientAngle;

            if (result > Math.PI)
            {
                result -= 2 * Math.PI;
            }
            else if (result < -Math.PI)
            {
                result += 2 * Math.PI;
            }

            return(result);
        }