예제 #1
0
 public void ShouldThrowExceptionWhenThresholdIsNegative()
 {
     using (var image = new MagickImage())
     {
         Assert.Throws <ArgumentException>("settings", () => image.Deskew(new Percentage(-1)));
     }
 }
예제 #2
0
 public void ShouldThrowExceptionWhenSettingsIsNull()
 {
     using (var image = new MagickImage())
     {
         Assert.Throws <ArgumentNullException>("settings", () => image.Deskew(null));
     }
 }
예제 #3
0
 public override MagickImage ApplyFilter(MagickImage image)
 {
     image.BackgroundColor = MagickColor.FromRgb(0, 0, 0);
     image.Deskew(new Percentage(Threshold));
     image.RePage();
     return(image);
 }
예제 #4
0
 public IEnumerable <byte> PreProcess(IEnumerable <byte> bitmap)
 {
     using (var processed = new MagickImage(bitmap.ToArray()))
     {
         processed.Deskew(new Percentage(60));
         return(processed.ToByteArray());
     }
 }
예제 #5
0
            public void ShouldReturnTheAngle()
            {
                using (var image = new MagickImage(Files.LetterJPG))
                {
                    var angle = image.Deskew(new Percentage(10));

                    Assert.InRange(angle, 7.01, 7.02);
                }
            }
예제 #6
0
            public void ShouldReturnTheAngle()
            {
                using (var image = new MagickImage(Files.LetterJPG))
                {
                    var angle = image.Deskew(new Percentage(10));

                    Assert.AreEqual(7.01, angle, 0.01);
                }
            }
예제 #7
0
        private void UnrotateImage(MagickImage image)
        {
            if (!Unrotate)
            {
                return;
            }

            image.BackgroundColor = BackgroundColor;
            image.Deskew((Percentage)40);
        }
        public void CreateNewImageFrom(string source, string target)
        {
            using (MagickImage image = new MagickImage(source))
            {
                image.Deskew(DeskewPercentage);
                image.Despeckle();
                image.Grayscale(PixelIntensityMethod.Rec709Luminance);

                image.Write(target);
            }
        }
예제 #9
0
            public void ShouldThrowExceptionWhenSettingsThresholdIsNegative()
            {
                using (var image = new MagickImage())
                {
                    var settings = new DeskewSettings
                    {
                        Threshold = new Percentage(-1),
                    };

                    Assert.Throws <ArgumentException>("settings", () => image.Deskew(settings));
                }
            }
예제 #10
0
            public void ShouldDeskewTheImage()
            {
                using (var image = new MagickImage(Files.LetterJPG))
                {
                    image.ColorType = ColorType.Bilevel;

                    ColorAssert.Equal(MagickColors.White, image, 471, 92);

                    image.Deskew(new Percentage(10));

                    ColorAssert.Equal(new MagickColor("#007400740074"), image, 471, 92);
                }
            }
예제 #11
0
            public void ShouldUseAutoCrop()
            {
                using (var image = new MagickImage(Files.LetterJPG))
                {
                    var settings = new DeskewSettings
                    {
                        AutoCrop  = true,
                        Threshold = new Percentage(10),
                    };

                    image.Deskew(settings);

                    Assert.Equal(480, image.Width);
                    Assert.Equal(577, image.Height);
                }
            }
        private void bwImageProcess_DoWork(object sender, DoWorkEventArgs e)
        {
            if (this.m_processQueue.Count > 0)
            {
                string fname = "";
                lock (this.m_syncObject)
                {
                    fname = m_processQueue.Dequeue();
                }

                byte[] tempImg = File.ReadAllBytes(fname);
                string ocrText = "";

                MagickReadSettings settings = new MagickReadSettings();
                using (MagickImage image = new MagickImage(tempImg, settings))
                {
                    image.Quality = scannedQuality;
                    image.Deskew(new Percentage(100));
                    image.Trim();
                    image.AutoOrient();
                    File.Delete(fname);
                    image.Write(fname);

                    Bitmap          bmp             = Grayscale.CommonAlgorithms.BT709.Apply(image.ToBitmap());
                    Threshold       thresholdFilter = new Threshold(127);
                    Bitmap          searchOcr       = thresholdFilter.Apply(bmp);
                    TesseractEngine engine          = new TesseractEngine("tessdata", "eng", EngineMode.Default);
                    Page            page            = engine.Process(searchOcr);
                    ocrText = page.GetText();
                }


                fileList.Add(fname);
                DataRow r = dtDoc.NewRow();
                r["DocFilename"] = fname;
                r["DocValue"]    = "0";
                r["DocSize"]     = string.Format("{0:n0} KB", Math.Round((double)new FileInfo(fname).Length / 1024));
                r["DocOcr"]      = ocrText;
                dtDoc.Rows.Add(r);
                e.Result = r;
            }
        }
예제 #13
0
        public IEnumerable <byte> PreProcess(IEnumerable <byte> bitmap)
        {
            using (var processed = new MagickImage(bitmap.ToArray()))
            {
                processed.ColorSpace = ColorSpace.Gray;
                processed.ColorType  = ColorType.Grayscale;

                processed.Normalize();

                // Denoise
                using (var denoise = processed.Clone())
                {
                    denoise.ColorSpace = ColorSpace.Gray;
                    denoise.Negate();
                    denoise.AdaptiveThreshold(10, 10, new Percentage(5));
                    denoise.ContrastStretch(new Percentage(0));
                    processed.Composite(denoise, CompositeOperator.CopyAlpha);
                }
                processed.Opaque(MagickColors.Transparent, MagickColors.White);
                processed.Alpha(AlphaOption.Off);

                // Deskew
                processed.BackgroundColor = MagickColors.White;
                processed.Deskew(new Percentage(40));

                // Sharpen
                processed.Sharpen(0, 1);

                // Saturate
                processed.Modulate(new Percentage(100), new Percentage(200), new Percentage(100));

                // Trim
                processed.Trim();
                processed.RePage();

                processed.Compose     = CompositeOperator.Over;
                processed.BorderColor = MagickColors.White;
                processed.Border(15);

                return(processed.ToByteArray());
            }
        }
        public static void Run([BlobTrigger("inbox/{inputFilename}", Connection = "StorageAccountConnString")] Stream inputStream, string inputFilename,
                               [Blob("outbox/out-{inputFilename}", FileAccess.Write, Connection = "StorageAccountConnString")] Stream outputStream, ILogger log)
        {
            log.LogInformation($"STEP: trigger fired for file:{inputFilename}, Size: {inputStream.Length} Bytes");

            using (MagickImage image = new MagickImage(inputStream))
            {
                log.LogInformation($"STEP: Read image {inputFilename} with {image.BaseWidth} x {image.BaseHeight} in {image.Format.ToString()}");

                // Step 0 - does nothing in the sample images I used
                image.AutoOrient();

                // Step 1 - Deskew
                image.BackgroundColor = MagickColor.FromRgb(0, 0, 0);
                image.Deskew(new Percentage(1)); // documentation suggests "A threshold of 40% works for most images" but 1% seems to work well
                IMagickImage rotatedImage = image.Clone();
                log.LogInformation($"STEP: Deskewed {inputFilename}");

                // Step 2 - Apply threshold to transform in black and white image
                image.AutoThreshold(AutoThresholdMethod.OTSU);
                log.LogInformation($"STEP: Applied OTSU to {inputFilename}");

                // Step 3 - find the regions (blocs) in the image and group them if large enough
                IEnumerable <ConnectedComponent> components = null;
                ConnectedComponentsSettings      ccs        = new ConnectedComponentsSettings();
                ccs.AreaThreshold = 500 * 500.0; // 500x500 -- seems to be pointless, many more regions are returned
                ccs.Connectivity  = 8;
                components        = image.ConnectedComponents(ccs);

                // if there are multiple blocs, consolidate them in a larger block
                if (components != null && components.Count() > 0)
                {
                    log.LogInformation($"STEP: Looked for regions in {inputFilename}, there are {components.Count()}");

                    // filter out the smaller rectangles, as the AreaThreshold parameter seems not to be working
                    List <ConnectedComponent> biggerComponents = components.Where(cc => cc.Height * cc.Width >= 250000 && cc.Height * cc.Width != image.Width * image.Height) /*.OrderByDescending(i => i.Height * i.Width)*/.ToList();
                    int topLeftX = biggerComponents[0].X, topLeftY = biggerComponents[0].Y, bottomRightX = biggerComponents[0].Width + topLeftX, bottomRightY = biggerComponents[0].Height + topLeftY;

                    foreach (ConnectedComponent cc in biggerComponents)
                    {
                        #region Debug -- draw the regions on the image
                        //DrawableStrokeColor strokeColor = new DrawableStrokeColor(new MagickColor("yellow"));
                        //DrawableStrokeWidth stokeWidth = new DrawableStrokeWidth(3);
                        //DrawableFillColor fillColor = new DrawableFillColor(new MagickColor(50, 50, 50, 128));
                        //DrawableRectangle dr = new DrawableRectangle(cc.X, cc.Y, cc.X + cc.Width, cc.Y + cc.Height);
                        //rotatedImage.Draw(dr, strokeColor, stokeWidth, fillColor);
                        #endregion

                        if (cc.X < topLeftX)
                        {
                            topLeftX = cc.X;
                        }

                        if (cc.Y < topLeftY)
                        {
                            topLeftY = cc.Y;
                        }

                        if (cc.X + cc.Width > bottomRightX)
                        {
                            bottomRightX = cc.X + cc.Width;
                        }

                        if (cc.Y + cc.Height > bottomRightY)
                        {
                            bottomRightY = cc.Y + cc.Height;
                        }
                    }

                    #region Debug -- draw the bounding box on the image
                    //DrawableStrokeColor strokeColor2 = new DrawableStrokeColor(new MagickColor("purple"));
                    //DrawableStrokeWidth stokeWidth2 = new DrawableStrokeWidth(3);
                    //DrawableFillColor fillColor2 = new DrawableFillColor(new MagickColor(50, 50, 50, 128));
                    //DrawableRectangle dr2 = new DrawableRectangle(topLeftX, topLeftY, bottomRightX, bottomRightY);
                    //rotatedImage.Draw(dr2, strokeColor2, stokeWidth2, fillColor2);
                    #endregion

                    // Step 4 - Crop the image
                    MagickGeometry mg = new MagickGeometry(topLeftX, topLeftY, bottomRightX - topLeftX, bottomRightY - topLeftY);
                    rotatedImage.RePage();  // this is needed because otherwise the crop is relative to the page information and sometimes this leads to an incorrect crop
                    rotatedImage.Crop(mg);

                    log.LogInformation($"STEP: Cropped {inputFilename} to fit existing large regions");
                }
                else
                {
                    log.LogInformation($"STEP: Looked for large regions in {inputFilename}, none were found, skipping crop");
                }

                // Step 5 - Resize the image to 1200px width (todo: move to configuration)
                int originalWidth  = rotatedImage.BaseWidth;
                int originalHeight = rotatedImage.BaseHeight;
                rotatedImage.Resize(1200, 0); // make width 1200, height proportional
                log.LogInformation($"STEP: Resized {inputFilename} from {originalWidth}x{originalHeight} to {image.BaseWidth}x{image.BaseHeight}");

                // Step 6 - write out as Jpeg with 70% quality
                rotatedImage.Format  = MagickFormat.Jpeg;
                rotatedImage.Quality = 70;
                rotatedImage.Write(outputStream);
                log.LogInformation($"STEP: Wrote out {inputFilename} as JPEG");
            }

            log.LogInformation($"STEP: Processing of {inputFilename} done");
        }