如何消除扫描表格中的偏斜?

huangapple go评论70阅读模式
英文:

How to get rid of skewness in scanned form?

问题

以下是翻译后的内容:

我必须构建一个程序,用于处理倾斜的表格(已扫描的图像)以进行图像处理。第一步是消除倾斜。我已成功获取图像的轮廓,并且正在尝试执行“four_point_transform”,如此帖子中所示:https://stackoverflow.com/questions/60018244/remove-top-section-of-image-above-border-line-to-detect-text-document。然而,我的代码失败了,原因是:

错误

java.lang.RuntimeException: OpenCV(4.4.0) C:\projects\javacpp-presets\opencv\cppbuild\windows-x86_64\opencv-4.4.0\modules\imgproc\src\imgwarp.cpp:3391: error: (-215:Assertion failed) src.checkVector(2, CV_32F) == 4 && dst.checkVector(2, CV_32F) == 4 in function 'cv::getPerspectiveTransform'

代码

  protected static void fixSkeweness(Mat mat) {
        Mat mask = new Mat();
        Mat gray = new Mat();
        Mat denoised = new Mat();
        Mat bin = new Mat();
        Mat hierarchy = new Mat();
        MatVector contours = new MatVector();

        cvtColor(mat, gray, COLOR_BGR2GRAY);
        // 标准化
        GaussianBlur(gray, denoised, new Size(5, 5), 0);
        threshold(denoised, mask, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
        normalize(gray, gray, 0, 255, NORM_MINMAX, -1, mask);
        // 转换为二进制图像
        threshold(gray, bin, 150, 255, THRESH_BINARY);
        // 查找轮廓
        findContours(bin, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE);
        long contourCount = contours.size();
        System.out.println("轮廓数量:" + contourCount);

        double maxArea = 0;
        int maxAreaId = 0;
        for (int i = 0; i < contourCount; ++i) {
            // 计算每个轮廓的面积
            Mat contour = contours.get(i);
            double area = contourArea(contour);
            if (area > maxArea) {
                maxAreaId = i;
                maxArea = area;
            }
        }

        Double peri = arcLength(contours.get(maxAreaId), true);
        Mat newcontour = new Mat();
        approxPolyDP(contours.get(maxAreaId), newcontour, 0.02 * peri, true);
        Mat result = new Mat();
        getPerspectiveTransform(newcontour.reshape(4, 2), result);
        imwrite("src/test/resources/isDataPage/fourPointTransform.jpg", result);
    }

代码中失败的行是:

getPerspectiveTransform(newcontour.reshape(4, 2), result);

我可以得到一些帮助来让这个工作起来吗?

示例图像:

如何消除扫描表格中的偏斜?

根据建议的答案的工作代码

protected static Mat findBiggestContour(Mat mat) {
    Mat mask = new Mat();
    Mat gray = new Mat();
    Mat denoised = new Mat();
    Mat bin = new Mat();
    Mat hierarchy = new Mat();
    MatVector contours = new MatVector();

    // 预处理图像
    cvtColor(mat, gray, COLOR_BGR2GRAY);
    threshold(gray, bin, 0, 255, THRESH_BINARY_INV + THRESH_OTSU);
    findContours(bin, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);

    double maxArea = 0;
    int maxAreaId = 0;

    for (int i = 0; i < contours.size(); ++i) {
        // 计算每个轮廓的面积
        Mat contour = contours.get(i);
        double area = contourArea(contour);

        if (area > 5000 && i != 0) {
            maxAreaId = i;
            maxArea = area;
        }
    }

    // 获取最小面积矩形并将其反转
    RotatedRect rect = minAreaRect(contours.get(maxAreaId));
    float newAngle = rect.angle();

    if (rect.angle() < 45) {
        newAngle = newAngle + 90;
    }
    RotatedRect angle = rect.angle(newAngle);

    int h = mat.size().height();
    int w = mat.size().width();

    int centerW = w / 2;
    int centerH = h / 2;
    
    // 找到旋转矩阵并应用它
    Point2f center = new Point2f(centerW, centerH);
    Mat m = getRotationMatrix2D(center, angle.angle(), 1.0);
    Mat rotated = new Mat();

    warpAffine(mat, rotated, m, new Size(w, h), INTER_CUBIC, BORDER_REPLICATE, new Scalar(10, 10));
    imwrite("src/test/resources/tmp2/rotrated.png", rotated);

    return rotated;
}
英文:

I have to build a program that takes in skewed forms (images that have been scanned) for image processing. The first step is to get rid of the skeweness. I'm successfully getting the contours of the image, and I'm attempting to do a four_point_transform as presented in this post https://stackoverflow.com/questions/60018244/remove-top-section-of-image-above-border-line-to-detect-text-document . However, my code is failing due to:

Error

java.lang.RuntimeException: OpenCV(4.4.0) C:\projects\javacpp-presets\opencv\cppbuild\windows-x86_64\opencv-4.4.0\modules\imgproc\src\imgwarp.cpp:3391: error: (-215:Assertion failed) src.checkVector(2, CV_32F) == 4 &amp;&amp; dst.checkVector(2, CV_32F) == 4 in function &#39;cv::getPerspectiveTransform

Code

  protected  static void fixSkeweness(Mat mat){

        Mat mask = new Mat();
        Mat gray = new Mat();
        Mat denoised = new Mat();
        Mat bin = new Mat();
        Mat hierarchy = new Mat();
        MatVector contours = new MatVector();

        cvtColor(mat, gray, COLOR_BGR2GRAY);
        //Normalize
        GaussianBlur(gray, denoised, new Size(5, 5), 0);
        threshold(denoised, mask, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
        normalize(gray, gray, 0, 255, NORM_MINMAX, -1, mask);
        // Convert image to binary
        threshold(gray, bin, 150, 255, THRESH_BINARY);
        // Find contours
        findContours(bin, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE);
        long contourCount = contours.size();
        System.out.println(&quot;Countour count &quot; + contourCount);

        double maxArea = 0;
        int maxAreaId = 0;
        for (int i = 0; i &lt; contourCount; ++i) {
            // Calculate the area of each contour
            Mat contour = contours.get(i);
            double area = contourArea(contour);
            if(area &gt; maxArea){
                maxAreaId = i;
                maxArea = area;
            }

        }


        Double peri = arcLength(contours.get(maxAreaId), true);
        Mat newcontour = new Mat();
        approxPolyDP(contours.get(maxAreaId), newcontour,0.02 * peri, true);
        Mat result = new Mat();
        getPerspectiveTransform(newcontour.reshape(4,2), result);
        imwrite(&quot;src/test/resources/isDataPage/fourPointTransform.jpg&quot;, result);

    }

The line of code that is failing is:

getPerspectiveTransform(newcontour.reshape(4,2), result);

Can I get some help to get this working, please?

Example Image:

如何消除扫描表格中的偏斜?

Working code as per suggested answer

protected static Mat findBiggestContour(Mat mat){
    Mat mask = new Mat();
    Mat gray = new Mat();
    Mat denoised = new Mat();
    Mat bin = new Mat();
    Mat hierarchy = new Mat();
    MatVector contours = new MatVector();

    //Pre-process image
    cvtColor(mat, gray, COLOR_BGR2GRAY);
    threshold(gray, bin, 0, 255, THRESH_BINARY_INV + THRESH_OTSU);
    findContours(bin, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);


    double maxArea = 0;
    int maxAreaId = 0;

    for (int i = 0; i &lt; contours.size(); ++i) {

        // Calculate the area of each contour
        Mat contour = contours.get(i);
        double area = contourArea(contour);

        if(area &gt; 5000 &amp;&amp; i!=0){
            maxAreaId = i;
            maxArea = area;
        }

    }

    //Get Min Area Rect and inverse it
    RotatedRect rect = minAreaRect(contours.get(maxAreaId));
    float newAngle = rect.angle();

    if (rect.angle() &lt; 45){
        newAngle = newAngle + 90;
    }
    RotatedRect angle =rect.angle( newAngle);

    int h = mat.size().height();
    int w = mat.size().width();

    int centerW =  w/2;
    int centerH = h/2;
    
    //find rotation matrix and apply it woohoo
    Point2f center = new Point2f(centerW, centerH);
    Mat m = getRotationMatrix2D(center, angle.angle(), 1.0);
    Mat rotated = new Mat();

    warpAffine(mat,rotated,m, new Size(w, h),INTER_CUBIC,BORDER_REPLICATE,new Scalar(10,10));
    imwrite(&quot;src/test/resources/tmp2/rotrated.png&quot;,rotated);

    return rotated;
}

答案1

得分: 0

getPerspectiveTransform()的工作方式不同请参阅我的注释)。然而我发现`minAreaRect()`在这里更合适我没有准备好的Java环境所以这里是Python代码我希望您在转换时不会遇到困难

img = cv2.imread'images/form.png'
gray = cv2.cvtColorimgcv2.COLOR_BGR2GRAY

正如您所做的那样进行一些预处理
尽管您的源图像非常干净如果它们都是这样的
我不会使用模糊处理因为它会使表单边界不太明显
 gray = cv2.blurgray,(55))
thresh = cv2.thresholdgray0255cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU[1]

查找最大的轮廓假设它将是一个漂亮的矩形
ctrshier = cv2.findContoursthreshcv2.RETR_LISTcv2.CHAIN_APPROX_SIMPLE
largest_ctr_idx = maxrangelenctrs)),key = lambda icv2.contourAreactrs [i]))

获取轮廓的旋转角度
angle = cv2.minAreaRectctrs [largest_ctr_idx][-1]
if angle < -45
    angle + = 90

查找旋转矩阵并应用它
hw = img.shape [2]
center =w // 2h // 2
m = cv2.getRotationMatrix2Dcenterangle1.0
rotated = cv2.warpAffineimgm,(wh),flags = cv2.INTER_CUBIC
    borderMode = cv2.BORDER_REPLICATE

找到的轮廓

[![enter image description here] [1]] [1]

校正后的图像

[![enter image description here] [2]] [2]
英文:

getPerspectiveTransform() is working some other way (see my comment). However, I found minAreaRect() as more suitable method here. I have no prepared java enviroment so here is python code. I hope you will have no difficulties while converting it.

<!-- language: python -->

img = cv2.imread(&#39;images/form.png&#39;)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# some preprocessing as you did
# your src image is pretty clean though, and if they all are like that,
#   I wouldn&#39;t use blur as it makes form borders less obvious
# gray = cv2.blur(gray, (5, 5))
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# find the largest contour assuming it will be some nice rectangle
ctrs, hier = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
largest_ctr_idx = max(range(len(ctrs)), key=lambda i: cv2.contourArea(ctrs[i]))
# get the contour&#39;s rotation angle
angle = cv2.minAreaRect(ctrs[largest_ctr_idx])[-1]
if angle &lt; -45:
angle += 90
# find rotation matrix and apply it woohoo
h, w = img.shape[:2]
center = (w // 2, h // 2)
m = cv2.getRotationMatrix2D(center, angle, 1.0)
rotated = cv2.warpAffine(img, m, (w, h), flags=cv2.INTER_CUBIC,
borderMode=cv2.BORDER_REPLICATE)

Found contour:

如何消除扫描表格中的偏斜?

Deskewed image:

如何消除扫描表格中的偏斜?

huangapple
  • 本文由 发表于 2020年9月27日 06:02:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/64082909.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定