static public void DeskewAsColumnOfBlocks(ref Bitmap bitmap, int blockMaxLength, int blockMinGap, Size structuringElementSize, int contourMaxCount, double angleMaxDeviation, Color marginColor) { (float H, float V)dpi = (H : bitmap.HorizontalResolution, V : bitmap.VerticalResolution); using (Image <Rgb, byte> image = bitmap.ToImage <Rgb, byte>()) { bitmap.Dispose(); Size margin = getScaledBlockMargin(); Rgb marginRgb = new Rgb(marginColor); Image <Rgb, byte> deskewedImage = new Image <Rgb, byte>(image.Width + 2 * margin.Width, image.Height /*+ 2 * margin.Height*/, marginRgb); //int lastBlockBottomLeft = -1; //int lastBlockBottomRight = -1; Image <Gray, byte> image2 = image.Convert <Gray, byte>(); CvInvoke.BitwiseNot(image2, image2); //CvInvoke.Blur(image2, image2, new Size(3, 3), new Point(0, 0)); CvInvoke.GaussianBlur(image2, image2, new Size(25, 25), 5);//remove small spots CvInvoke.Threshold(image2, image2, 125, 255, ThresholdType.Otsu | ThresholdType.Binary); Mat se = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(5, 5), new Point(-1, -1)); CvInvoke.Dilate(image2, image2, se, new Point(-1, -1), 1, BorderType.Constant, CvInvoke.MorphologyDefaultBorderValue); //CvInvoke.Erode(image2, image2, se, new Point(-1, -1), 5, BorderType.Constant, CvInvoke.MorphologyDefaultBorderValue); //CvInvoke.BitwiseNot(image2, image2); //return image2.ToBitmap(); VectorOfVectorOfPoint cs = new VectorOfVectorOfPoint(); Mat h = new Mat(); CvInvoke.FindContours(image2, cs, h, RetrType.Tree, ChainApproxMethod.ChainApproxSimple); if (cs.Size < 1) { return; } Array hierarchy = h.GetData(); List <Contour> contours = new List <Contour>(); for (int i = 0; i < cs.Size; i++) { int p = (int)hierarchy.GetValue(0, i, Contour.HierarchyKey.Parent); if (p < 1) { contours.Add(new Contour(hierarchy, i, cs[i])); } } if (contours.Where(a => a.ParentId < 0).Count() < 2)//the only parent is the whole page frame { contours.RemoveAll(a => a.ParentId < 0); } else { contours.RemoveAll(a => a.ParentId >= 0); } contours = contours.OrderBy(a => a.BoundingRectangle.Bottom).ToList(); for (int blockY = 0; blockY < image.Height;) { int blockBottom = image.Height - 1; Tuple <Contour, Contour> lastSpan = null; for (; contours.Count > 0;) { Contour c = contours[0]; contours.RemoveAt(0); if (contours.Count > 0) { Contour minTop = contours.Aggregate((a, b) => a.BoundingRectangle.Top < b.BoundingRectangle.Top ? a : b); if (c.BoundingRectangle.Bottom + blockMinGap <= minTop.BoundingRectangle.Top) { lastSpan = new Tuple <Contour, Contour>(c, minTop); } } if (c.BoundingRectangle.Bottom > blockY + blockMaxLength && lastSpan != null) { blockBottom = lastSpan.Item1.BoundingRectangle.Bottom + blockMinGap / 2; break; } } Rectangle blockRectangle = new Rectangle(0, blockY, image2.Width, blockBottom + 1 - blockY); Image <Rgb, byte> blockImage = image.Copy(blockRectangle); Image <Rgb, byte> deskewedBlockImage = deskew(blockImage, structuringElementSize, contourMaxCount, angleMaxDeviation, margin, marginRgb); //int blockTopLeft = findOffsetLeft(deskewedBlockImage, 10).X; //int blockTopRight = findOffsetRight(deskewedBlockImage, 10).X; //if (lastBlockBottomLeft < 0) // lastBlockBottomLeft = blockTopLeft; //if (lastBlockBottomRight < 0) // lastBlockBottomRight = blockTopRight; //deskewedBlockImage.ROI = new Rectangle(blockTopLeft, 0, blockTopRight - blockTopLeft, deskewedBlockImage.Height); //deskewedImage.ROI = new Rectangle(lastBlockBottomLeft - ((blockTopRight - blockTopLeft) - (lastBlockBottomRight - lastBlockBottomLeft)) / 2, blockRectangle.Y, blockTopRight - blockTopLeft, deskewedBlockImage.Height); deskewedBlockImage.ROI = new Rectangle(0, margin.Height, deskewedBlockImage.Width, deskewedBlockImage.Height - 2 * margin.Height); deskewedImage.ROI = new Rectangle(0, blockRectangle.Y, deskewedBlockImage.ROI.Width, deskewedBlockImage.ROI.Height); deskewedBlockImage.CopyTo(deskewedImage); deskewedImage.ROI = Rectangle.Empty; //lastBlockBottomLeft = findOffsetLeft(deskewedBlockImage, -10).X; //lastBlockBottomRight = findOffsetRight(deskewedBlockImage, -10).X; // break; blockY = blockBottom + 1; } deskewedImage.ROI = getCropped(deskewedImage, marginRgb);//crop bitmap = deskewedImage?.ToBitmap(); } bitmap.SetResolution(dpi.H, dpi.V); }
static public void DeskewAsColumnOfBlocks(ref Bitmap bitmap, int blockMaxHeight, int minBlockSpan) { using (Image <Rgb, byte> image = bitmap.ToImage <Rgb, byte>()) { bitmap.Dispose(); //return image.ToBitmap(); Image <Rgb, byte> deskewedimage = new Image <Rgb, byte>(image.Size); Image <Gray, byte> image2 = image.Convert <Gray, byte>(); CvInvoke.BitwiseNot(image2, image2); //CvInvoke.Blur(image2, image2, new Size(3, 3), new Point(0, 0)); CvInvoke.GaussianBlur(image2, image2, new Size(25, 25), 5);//remove small spots CvInvoke.Threshold(image2, image2, 125, 255, ThresholdType.Otsu | ThresholdType.Binary); Mat se = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(5, 5), new Point(-1, -1)); CvInvoke.Dilate(image2, image2, se, new Point(-1, -1), 1, BorderType.Constant, CvInvoke.MorphologyDefaultBorderValue); //CvInvoke.Erode(image2, image2, se, new Point(-1, -1), 5, BorderType.Constant, CvInvoke.MorphologyDefaultBorderValue); //CvInvoke.BitwiseNot(image2, image2); //return image2.ToBitmap(); VectorOfVectorOfPoint cs = new VectorOfVectorOfPoint(); Mat h = new Mat(); CvInvoke.FindContours(image2, cs, h, RetrType.Tree, ChainApproxMethod.ChainApproxSimple); if (cs.Size < 1) { return; } Array hierarchy = h.GetData(); List <Contour> contours = new List <Contour>(); for (int i = 0; i < cs.Size; i++) { int p = (int)hierarchy.GetValue(0, i, Contour.HierarchyKey.Parent); if (p < 1) { contours.Add(new Contour(hierarchy, i, cs[i])); } } if (contours.Where(a => a.ParentId < 0).Count() < 2)//the only parent is the whole page frame { contours.RemoveAll(a => a.ParentId < 0); } else { contours.RemoveAll(a => a.ParentId >= 0); } contours = contours.OrderBy(a => a.BoundingRectangle.Bottom).ToList(); for (int blockY = 0; blockY < image.Height;) { int blockBottom = image.Height - 1; Tuple <Contour, Contour> lastSpan = null; for (; contours.Count > 0;) { Contour c = contours[0]; contours.RemoveAt(0); if (contours.Count > 0) { Contour minTop = contours.Aggregate((a, b) => a.BoundingRectangle.Top < b.BoundingRectangle.Top ? a : b); if (c.BoundingRectangle.Bottom + minBlockSpan <= minTop.BoundingRectangle.Top) { lastSpan = new Tuple <Contour, Contour>(c, minTop); } } if (c.BoundingRectangle.Bottom > blockY + blockMaxHeight && lastSpan != null) { blockBottom = lastSpan.Item1.BoundingRectangle.Bottom + minBlockSpan / 2; break; } } Rectangle blockRectangle = new Rectangle(0, blockY, image2.Width, blockBottom + 1 - blockY); Image <Rgb, byte> blockImage = image.Copy(blockRectangle); blockImage = deskew(blockImage); deskewedimage.ROI = blockRectangle; blockImage.CopyTo(deskewedimage); deskewedimage.ROI = Rectangle.Empty; // break; blockY = blockBottom + 1; } bitmap = deskewedimage?.ToBitmap(); } }