文档图像倾斜校正算法(2)——直线检测倾斜校正

文档图像倾斜校正算法(2)——直线检测倾斜校正

原理:检测文本块中的直线,根据直线的倾斜角完成倾斜矫正
适用范围:为避免背景中可能存在的直线干扰,应先截取到图像中的带有表格线的区域,在该区域上进行直线检测,利用检测到的直线的倾斜角完成图像的矫正。
在这里插入图片描述

#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <vector>
#include <numeric>
#define MY_SKEW 14

//图像旋转1:旋转(截取图像)Crop
//         Mat img :图像输入,单通道或者三通道
//         Mat & imgout :图像输出
//         int degree :图像要旋转的角度
//         int border_value:图像旋转填充值
int rotateImage1(Mat img,Mat & imgout, int degree,int border_value)
{
    if( img.empty())
        return 1;
    degree = -degree;//warpAffine默认的旋转方向是逆时针,所以加负号表示转化为顺时针
    double angle = degree  * CV_PI / 180.; // 弧度  
    double a = sin(angle), b = cos(angle);
    int width = img.cols;
    int height = img.rows;
    int width_rotate = int(width * fabs(b)-height * fabs(a));//height * fabs(a) +
    int height_rotate = int(height * fabs(b)-width * fabs(a));//width * fabs(a) +
    if(width_rotate<=20||height_rotate<=20)
    {
        width_rotate = 20;
        height_rotate = 20;
    }
    //旋转数组map
    // [ m0  m1  m2 ] ===>  [ A11  A12   b1 ]
    // [ m3  m4  m5 ] ===>  [ A21  A22   b2 ]
    float map[6];
    Mat map_matrix = Mat(2, 3, CV_32F, map);
    // 旋转中心
    CvPoint2D32f center = cvPoint2D32f(width / 2, height / 2);
    CvMat map_matrix2 = map_matrix;
    cv2DRotationMatrix(center, degree, 1.0, &map_matrix2);//计算二维旋转的仿射变换矩阵
    map[2] += (width_rotate - width) / 2;
    map[5] += (height_rotate - height) / 2;
    //Mat img_rotate;
    //对图像做仿射变换
    //CV_WARP_FILL_OUTLIERS - 填充所有输出图像的象素。
    //如果部分象素落在输入图像的边界外,那么它们的值设定为 fillval.
    //CV_WARP_INVERSE_MAP - 指定 map_matrix 是输出图像到输入图像的反变换,
    int chnnel =img.channels();
    if(chnnel == 3)
        warpAffine(img, imgout, map_matrix, Size(width_rotate, height_rotate), 1, 0, Scalar(border_value,border_value,border_value));
    else
        warpAffine(img, imgout, map_matrix, Size(width_rotate, height_rotate), 1, 0, border_value);
    return 0;
}

//投影倾斜校正:增值税倾斜矫正方法举例
//         const Mat rgbimgin :图像输入,三通道
//         Mat & rgbimgout :矫正后的图像输出
//         int &theta :图像倾斜的角度
int skew_correction_line(const Mat rgbimgin,  Mat & rgbimgout, int &theta)
{

    if (rgbimgin.empty() || rgbimgin.channels() != 3)
    {
        return 1;
    }

    Mat imgout_crop = rgbimgin.clone();

    Mat imgout;
    float zoom_ratio = 400.0 / imgout_crop.rows;
    resize(imgout_crop, imgout, Size(0, 0), zoom_ratio, zoom_ratio, 1);
    Mat Gray;
    cvtColor(imgout, Gray, COLOR_RGB2GRAY);
    medianBlur(Gray, Gray, 3);
    Mat Bin;
    adaptiveThreshold(Gray, Bin, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, 111, 5.0);
    Bin = 255 - Bin;
    vector<Vec4i> lines;
    HoughLinesP(Bin, lines, 1, CV_PI / 180, 100, 100, 4);
    if (lines.size() <= 0)
    {
        theta = 0;
        rgbimgout = rgbimgin.clone();
        return 0;
    }
    Mat  Lineimg(Bin.rows, Bin.cols, CV_8UC1, Scalar::all(255));
    int result = 0;
    for (size_t i = 0; i < lines.size(); i++)
    {
        Vec4i l = lines[i];
        line(Lineimg, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0), 1, CV_AA);
        float param = float(int(l[1]) - int(l[3])) / float(abs(l[2] - l[0]));
        int tt = atan(param) * 180 / PI;
        if (tt > 45)
            tt = tt - 90;
        if (tt < -45)
            tt = 90 + tt;
        result = result + tt;
    }
    for (size_t i = 0; i < lines.size(); i++)
    {
        Vec4i l = lines[i];
        line(imgout, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(186, 88, 255), 1, CV_AA);
    }
    theta = result / int(lines.size());
    rotateImage1(rgbimgin, rgbimgout, theta, 0);
    return 0;
}

版权声明:本文为qq_19655645原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。