protected virtual void CheckCenterLine(Bitmap image) { var tmpImage = image.Copy(new Rectangle(0, 0, image.Width, image.Height)); var tmpImageData = tmpImage.LockBits(new Rectangle(new System.Drawing.Point(0, 0), tmpImage.Size), ImageLockMode.ReadWrite, tmpImage.PixelFormat); Drawing.Line(tmpImageData, new IntPoint(0, 0), new IntPoint(0, tmpImageData.Height), Color.White); tmpImage.UnlockBits(tmpImageData); OCRLessonReport.Imaging.HoughLineTransformation lineTransform = new OCRLessonReport.Imaging.HoughLineTransformation(); HoughLineRequestSettings vSettings = new HoughLineRequestSettings { HorizontalLines = false, VerticalLines = true }; var hWidth = tmpImage.Width / 2; var hHeight = tmpImage.Height / 2; lineTransform.ProcessImage(tmpImage, vSettings); HoughLine[] vLines = lineTransform.GetLinesByRelativeIntensity(0.9); var vLineCoordinates = vLines.Select(line => hWidth + line.Radius).Where(x => x > 1).OrderBy(x => x).ToArray(); if (vLineCoordinates.Length > 0) { var x0 = vLineCoordinates.FirstOrDefault() - 1; var x1 = vLineCoordinates.LastOrDefault() + 2; if (x1 - x0 > 10) { return; } var imageData = image.LockBits(new Rectangle(new System.Drawing.Point(0, 0), image.Size), ImageLockMode.ReadWrite, image.PixelFormat); Drawing.FillRectangle(imageData, new Rectangle(x0, 0, x1 - x0, image.Height), Color.Black); image.UnlockBits(imageData); } }
protected virtual double DetectRotation(Bitmap image) { //Hough line transformation OCRLessonReport.Imaging.HoughLineTransformation lineTransform = new OCRLessonReport.Imaging.HoughLineTransformation(); HoughLineRequestSettings settings = new HoughLineRequestSettings { HorizontalLines = false, VerticalLines = true, VerticalDeviation = Settings.SheetEdgeVerticalMaxAngle }; lineTransform.ProcessImage(image, settings); HoughLine[] lines = lineTransform.GetLinesByRelativeIntensity(Settings.SheetEdgeSensitivity); if (lines.Length < 1) { throw new Exception("Can't detect left edge"); } Func <HoughLine, double> getAngle = line => { double angle = 0; if (line.Theta > 90 && line.Radius > 0) { angle = 180 - line.Theta; } else if (line.Theta > 90 && line.Radius < 0) { angle = 180 - line.Theta; } else if (line.Theta < 90 && line.Radius > 0) { angle = -line.Theta; } else if (line.Theta < 90 && line.Radius < 0) { angle = -line.Theta; } return(angle); }; double avgAngle = lines.Select(l => getAngle(l)).Average(); return(avgAngle); }
protected virtual Bitmap ProcessCell(Bitmap cellImg, bool check = false) { //Build horizontal hough lines OCRLessonReport.Imaging.HoughLineTransformation lineTransform = new OCRLessonReport.Imaging.HoughLineTransformation(); HoughLineRequestSettings vSettings = new HoughLineRequestSettings { HorizontalLines = false, VerticalLines = true }; HoughLineRequestSettings hSettings = new HoughLineRequestSettings { HorizontalLines = true, VerticalLines = false }; lineTransform.ProcessImage(cellImg, vSettings); HoughLine[] vLines = lineTransform.GetLinesByRelativeIntensity(Settings.CellSensitivity); lineTransform.ProcessImage(cellImg, hSettings); HoughLine[] hLines = lineTransform.GetLinesByRelativeIntensity(Settings.CellSensitivity); var hWidth = cellImg.Width / 2; var hHeight = cellImg.Height / 2; var vLineCoordinates = vLines.Select(line => hWidth + line.Radius); var hLineCoordinates = hLines.Select(line => hHeight - line.Radius); var xEdges = GetCellEdges(vLineCoordinates, cellImg.Width, Settings.CellXEdgeWith, Settings.CellEdgeCutting); var yEdges = GetCellEdges(hLineCoordinates, cellImg.Height, Settings.CellYEdgeWith, Settings.CellEdgeCutting); cellImg = cellImg.Copy(new Rectangle(xEdges.Item1, yEdges.Item1, xEdges.Item2 - xEdges.Item1, yEdges.Item2 - yEdges.Item1)); //Check central line if (check) { CheckCenterLine(cellImg); } return(cellImg); }
/// <summary> /// Process an image building Hough map. /// </summary> /// /// <param name="image">Source image to process.</param> /// <param name="rect">Image's rectangle to process.</param> /// /// <exception cref="UnsupportedImageFormatException">Unsupported pixel format of the source image.</exception> /// public void ProcessImage(Bitmap image, Rectangle rect, HoughLineRequestSettings settings = null) { // check image format if (image.PixelFormat != PixelFormat.Format8bppIndexed) { throw new UnsupportedImageFormatException("Unsupported pixel format of the source image."); } // lock source image BitmapData imageData = image.LockBits( new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed); try { // process the image ProcessImage(new UnmanagedImage(imageData), rect, settings); } finally { // unlock image image.UnlockBits(imageData); } }
public virtual void ProccessImage(BackgroundWorker worker) { this.worker = worker; UpdateProgress(3); //Brightness and sharpen filters BrightnessCorrection cfilter = new BrightnessCorrection(Settings.Brightness); GaussianSharpen filter = new GaussianSharpen(4, 11); //Apply filters cfilter.ApplyInPlace(sourceBitmap); UpdateProgress(15); filter.ApplyInPlace(sourceBitmap); UpdateProgress(30); //Convert to gray var tmpImage = ConvertToGrayScale(sourceBitmap); UpdateProgress(35); //Cut edges tmpImage = CutEdgesAndInvert(tmpImage); UpdateProgress(40); //Get angle for rotating image var rotateAngle = DetectRotation(tmpImage); UpdateProgress(45); if (rotateAngle != 0) { RotateBilinear rotate = new RotateBilinear(rotateAngle, true); tmpImage = rotate.Apply(tmpImage); } //Build horizontal hough lines OCRLessonReport.Imaging.HoughLineTransformation lineTransform = new OCRLessonReport.Imaging.HoughLineTransformation(); HoughLineRequestSettings settings = new HoughLineRequestSettings { HorizontalLines = true, VerticalLines = false, HorizontalDeviation = 2 }; lineTransform.ProcessImage(tmpImage, settings); //Get horizontal line HoughLine[] lines = lineTransform.GetLinesByRelativeIntensity(Settings.HorizontalSensitivity); //Get half width and height for future calculations int hWidth = tmpImage.Width / 2; int hHeight = tmpImage.Height / 2; //Get line coordinates (Y axis only - horizontal lines) var lineCoordinates = lines.Select(line => hHeight - line.Radius); //Grouping coords by delta var groupedCoordinates = ImagingHelper.GroupingCoordinates(lineCoordinates, Settings.LineGroupingDelta); if (groupedCoordinates.Count <= Settings.HeaderStartLine) { throw new Exception("Invalid source. Can't be recognized"); } int headerLineY0 = groupedCoordinates[Settings.HeaderStartLine]; int headerLineY1 = groupedCoordinates[Settings.HeaderStartLine + 1]; //Copy header to new image var headerImage = tmpImage.Copy(new Rectangle(0, headerLineY0, tmpImage.Width, headerLineY1 - headerLineY0)); //Parse header to get header lines HoughLineRequestSettings headerSettings = new HoughLineRequestSettings { HorizontalLines = false, VerticalLines = true, VerticalDeviation = 1 }; lineTransform.ProcessImage(headerImage, headerSettings); Func <HoughLine, int, int> getRadius = (l, w) => { if (l.Theta > 90 && l.Theta < 180) { return(w - l.Radius); } else { return(w + l.Radius); } }; HoughLine[] headerLines = lineTransform.GetLinesByRelativeIntensity(Settings.VerticalSensitivity); //Get header vertical lines var headerLineCoordinates = headerLines.Select(line => getRadius(line, hWidth)); //Grouped lines var groupedheaderLineCoordinates = ImagingHelper.GroupingCoordinates(headerLineCoordinates, Settings.LineGroupingDelta); //Build cell map List <TableCell> cellMap = new List <TableCell>(); UpdateProgress(50); //Use tess engine for ocr using (TesseractEngine engine = new TesseractEngine(Settings.TessdataPath, Settings.TessdataLanguage)) { //Parse top header var x0 = groupedheaderLineCoordinates.FirstOrDefault(); var x1 = groupedheaderLineCoordinates.LastOrDefault(); var y0 = groupedCoordinates[0]; var y1 = groupedCoordinates[1]; int fullProgress = (groupedheaderLineCoordinates.Count - 1) * (groupedCoordinates.Count - Settings.BottomStartLine - 1 - Settings.HeaderStartLine); int curProgress = 0; var hImage = tmpImage.Copy(new Rectangle(x0, y0, x1 - x0, y1 - y0)); hImage = ProcessCell(hImage); using (var page = engine.Process(hImage, PageSegMode.SingleBlock)) { cellMap.Add(new TableCell(0, 0, TableCellType.MainHeader, hImage, page.GetText(), false)); } //Parse table for (int i = 0; i < groupedheaderLineCoordinates.Count - 1; i++) { int subjectArea = (i < Settings.ColumnSubjectStart - 1) ? 0 : 1; for (int j = Settings.HeaderStartLine; j < groupedCoordinates.Count - Settings.BottomStartLine - 1; j++) { int headerArea = (j == Settings.HeaderStartLine) ? 2 : 0; TableCellType cellType = (TableCellType)(subjectArea + headerArea); var cellImg = tmpImage.Copy(new Rectangle(groupedheaderLineCoordinates[i], groupedCoordinates[j], groupedheaderLineCoordinates[i + 1] - groupedheaderLineCoordinates[i], groupedCoordinates[j + 1] - groupedCoordinates[j])); if (cellType == TableCellType.Text || cellType == TableCellType.Header || cellType == TableCellType.HeaderRotated) { cellImg = ProcessCell(cellImg, i == Settings.NameStartLine); string text = String.Empty; if (cellType == TableCellType.HeaderRotated) { cellImg.RotateFlip(RotateFlipType.Rotate90FlipNone); } using (var page = engine.Process(cellImg, PageSegMode.SingleBlock)) { text = page.GetText(); } cellMap.Add(new TableCell(i, j, cellType, cellImg, text, false)); } else { cellImg = ProcessCell(cellImg); BilateralSmoothing bfilter = new BilateralSmoothing(); bfilter.KernelSize = 7; bfilter.SpatialFactor = 10; bfilter.ColorFactor = 60; bfilter.ColorPower = 0.5; bfilter.ApplyInPlace(cellImg); cellImg = FilterColors(cellImg, Settings.FilteringColor, ByteColor.Black, ByteColor.White); BlobCounter bcounter = new BlobCounter(); bcounter.ProcessImage(cellImg); var blobs = bcounter.GetObjects(cellImg, false); if (blobs.Length < 1) { continue; } var biggestBlob = blobs.OrderBy(b => b.Area).LastOrDefault(); var biggestBlobsImage = biggestBlob.Image.ToManagedImage(); cellMap.Add(new TableCell(i, j, cellType, biggestBlobsImage, GetMask(biggestBlobsImage).ToString(), GetMask(biggestBlobsImage))); } curProgress++; double reportProgress = (double)curProgress / (double)fullProgress * 50 + 50; UpdateProgress((int)reportProgress); } } } this.Cells = cellMap; UpdateProgress(100); }
/// <summary> /// Process an image building Hough map. /// </summary> /// /// <param name="image">Source unmanaged image to process.</param> /// <param name="rect">Image's rectangle to process.</param> /// /// <exception cref="UnsupportedImageFormatException">Unsupported pixel format of the source image.</exception> /// public void ProcessImage(UnmanagedImage image, Rectangle rect, HoughLineRequestSettings settings = null) { if (image.PixelFormat != PixelFormat.Format8bppIndexed) { throw new UnsupportedImageFormatException("Unsupported pixel format of the source image."); } // get source image size int width = image.Width; int height = image.Height; int halfWidth = width / 2; int halfHeight = height / 2; // make sure the specified rectangle recides with the source image rect.Intersect(new Rectangle(0, 0, width, height)); int startX = -halfWidth + rect.Left; int startY = -halfHeight + rect.Top; int stopX = width - halfWidth - (width - rect.Right); int stopY = height - halfHeight - (height - rect.Bottom); int offset = image.Stride - rect.Width; // calculate Hough map's width int halfHoughWidth = (int)Math.Sqrt(halfWidth * halfWidth + halfHeight * halfHeight); int houghWidth = halfHoughWidth * 2; houghMap = new short[houghHeight, houghWidth]; // do the job unsafe { byte *src = (byte *)image.ImageData.ToPointer() + rect.Top * image.Stride + rect.Left; // for each row for (int y = startY; y < stopY; y++) { // for each pixel for (int x = startX; x < stopX; x++, src++) { if (*src > 0) { // for each Theta value for (int theta = 0; theta < houghHeight; theta++) { if (settings != null && !settings.AllowedThetas.Contains(theta)) { continue; } int radius = (int)Math.Round(cosMap[theta] * x - sinMap[theta] * y) + halfHoughWidth; if ((radius < 0) || (radius >= houghWidth)) { continue; } houghMap[theta, radius]++; } } } src += offset; } } // find max value in Hough map maxMapIntensity = 0; for (int i = 0; i < houghHeight; i++) { for (int j = 0; j < houghWidth; j++) { if (houghMap[i, j] > maxMapIntensity) { maxMapIntensity = houghMap[i, j]; } } } CollectLines(); }
/// <summary> /// Process an image building Hough map. /// </summary> /// /// <param name="imageData">Source image data to process.</param> /// <param name="rect">Image's rectangle to process.</param> /// /// <exception cref="UnsupportedImageFormatException">Unsupported pixel format of the source image.</exception> /// public void ProcessImage(BitmapData imageData, Rectangle rect, HoughLineRequestSettings settings = null) { ProcessImage(new UnmanagedImage(imageData), rect, settings); }
/// <summary> /// Process an image building Hough map. /// </summary> /// /// <param name="imageData">Source image data to process.</param> /// /// <exception cref="UnsupportedImageFormatException">Unsupported pixel format of the source image.</exception> /// public void ProcessImage(BitmapData imageData, HoughLineRequestSettings settings = null) { ProcessImage(new UnmanagedImage(imageData), new Rectangle(0, 0, imageData.Width, imageData.Height), settings); }
/// <summary> /// Process an image building Hough map. /// </summary> /// /// <param name="image">Source image to process.</param> /// /// <exception cref="UnsupportedImageFormatException">Unsupported pixel format of the source image.</exception> /// public void ProcessImage(Bitmap image, HoughLineRequestSettings settings = null) { ProcessImage(image, new Rectangle(0, 0, image.Width, image.Height), settings); }