shimat / opencvsharp

OpenCV wrapper for .NET
Apache License 2.0
5.22k stars 1.13k forks source link

Need Help for Warpping and Deskewing #1635

Open kerberosargos opened 6 months ago

kerberosargos commented 6 months ago

Summary of your issue

I would like to fix word of text before scanning via Tesseract with OpenCvSharp. Code's snippet and images's results as following. I can not find warpping and deskewing image. Thank you in advance for your effort.

Example code:

private Mat warp(Mat sourceImage)
{
    var copySourceImage = new Mat();
    var colorSourceImage = new Mat();
    sourceImage.CopyTo(copySourceImage);
    sourceImage.CopyTo(colorSourceImage);

    Cv2.CvtColor(colorSourceImage, colorSourceImage, ColorConversionCodes.GRAY2RGB);

    var blurImage = new Mat();
    Cv2.GaussianBlur(copySourceImage, blurImage, new OpenCvSharp.Size(7, 7), 1);
    showMat(copySourceImage, "warp > blurImage", true);

    var grayInput = CreateGrayImage(blurImage);

    var cannyImage = new Mat();
    Cv2.Canny(grayInput, cannyImage, threshold1: 0, threshold2: 255);
    showMat(cannyImage, "warp > cannyImage", true);

    var dilateRectKernel = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(5, 5));
    Mat dilate = new Mat();
    Cv2.Dilate(cannyImage, dilate, dilateRectKernel, iterations: 4);
    showMat(dilate, "warp > dilate", true);

    Mat erode = new Mat();
    Cv2.Erode(dilate, erode, null, iterations: 1);
    showMat(erode, "warp > erode", true);

    OpenCvSharp.Point[][] contours;
    HierarchyIndex[] hierarchyIndexes;
    Cv2.FindContours(
        dilate,
        out contours,
        out hierarchyIndexes,
        mode: RetrievalModes.External,
        method: ContourApproximationModes.ApproxNone);

    if (contours.Length == 0)
    {
        throw new NotSupportedException("Couldn't find any object in the image.");
    }

    var orderedContours = contours.OrderByDescending(c => Cv2.ContourArea(c)).ToArray();

    // Find largest contour and surround in min area box
    var paperContour = orderedContours[0].ToList();

    var peri = Cv2.ArcLength(paperContour, true);

    var approx = Cv2.ApproxPolyDP(paperContour, 0.02 * peri, true).ToList();
    List<OpenCvSharp.Point2f> approx2 = new List<OpenCvSharp.Point2f>();
    List<OpenCvSharp.Point2f> paperContour2 = new List<OpenCvSharp.Point2f>();

    List<List<OpenCvSharp.Point>> paperContourPoints = new List<List<OpenCvSharp.Point>>() { { paperContour } };
    List<List<OpenCvSharp.Point>> paperApproxPoints = new List<List<OpenCvSharp.Point>>() { { approx } };

    Cv2.DrawContours(colorSourceImage, paperContourPoints, -1, Scalar.LimeGreen, 1, LineTypes.AntiAlias);
    Cv2.DrawContours(colorSourceImage, paperApproxPoints, -1, Scalar.Red, 1, LineTypes.AntiAlias);
    Cv2.Rectangle(colorSourceImage, Cv2.BoundingRect(approx), Scalar.Blue, 1, LineTypes.AntiAlias);

    showMat(colorSourceImage, "warp > colorSourceImage", true);

    foreach (var a in approx)
    {

        approx2.Add(new Point2f(a.X, a.Y));
    }

    foreach (var a in paperContour)
    {

        paperContour2.Add(new Point2f(a.X, a.Y));
    }

    Mat transmtx = Cv2.GetPerspectiveTransform(approx2, paperContour2);
    Mat transformed = new Mat(sourceImage.Rows, sourceImage.Cols, MatType.CV_8UC3);
    Cv2.WarpPerspective(sourceImage, transformed, transmtx, sourceImage.Size());
    showMat(sourceImage, "warp > sourceImage", true);
}

private void showMat(Mat sourceImage, string title, bool isSave = false, bool isWaitable = false)
{
    if (string.IsNullOrEmpty(title))
    {
        title = Guid.NewGuid().ToString();
    }

    // Cv2.ImShow(title, sourceImage);

    if (isSave)
    {
        sourceImage.SaveImage($"{imagesResultPath}{MakeValidFileName(title)}.jpg");
    }

    if (isWaitable)
    {
        Cv2.WaitKey();
    }
}

Output:

Source Image 615-warp___sourceimage

Canny Image 611-warp___cannyimage

Dilate Image 612-warp___dilate

Erode Image 613-warp___erode

Drawed Image 614-warp___colorsourceimage

Result 615-warp___sourceimage