public void ShouldThrowExceptionWhenThresholdIsNegative() { using (var image = new MagickImage()) { Assert.Throws <ArgumentException>("settings", () => image.Deskew(new Percentage(-1))); } }
public void ShouldThrowExceptionWhenSettingsIsNull() { using (var image = new MagickImage()) { Assert.Throws <ArgumentNullException>("settings", () => image.Deskew(null)); } }
public override MagickImage ApplyFilter(MagickImage image) { image.BackgroundColor = MagickColor.FromRgb(0, 0, 0); image.Deskew(new Percentage(Threshold)); image.RePage(); return(image); }
public IEnumerable <byte> PreProcess(IEnumerable <byte> bitmap) { using (var processed = new MagickImage(bitmap.ToArray())) { processed.Deskew(new Percentage(60)); return(processed.ToByteArray()); } }
public void ShouldReturnTheAngle() { using (var image = new MagickImage(Files.LetterJPG)) { var angle = image.Deskew(new Percentage(10)); Assert.InRange(angle, 7.01, 7.02); } }
public void ShouldReturnTheAngle() { using (var image = new MagickImage(Files.LetterJPG)) { var angle = image.Deskew(new Percentage(10)); Assert.AreEqual(7.01, angle, 0.01); } }
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); } }
public void ShouldThrowExceptionWhenSettingsThresholdIsNegative() { using (var image = new MagickImage()) { var settings = new DeskewSettings { Threshold = new Percentage(-1), }; Assert.Throws <ArgumentException>("settings", () => image.Deskew(settings)); } }
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); } }
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; } }
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"); }