美文网首页
opencv倾斜校正(C++版)

opencv倾斜校正(C++版)

作者: 帅气的我要加油 | 来源:发表于2019-05-26 11:20 被阅读0次

校正图片样例:

image image image

上图1\2\3分别为常见的几种需要倾斜校正处理的样例。

对于不同样式的图片倾斜校正的思路是不同的:

图1中边界信息明显,可以通过findcontours函数检测轮廓矩阵获得角度从而进行旋转校正。

图2中没有明显边界,但是每行文字信息比较明显,因此可以通过canny函数进行边缘检测,根据一行一行的文字信息确定角度从而进行校正。

图3是真实场景中随意的一张表单照片(重要信息打码啦~~),图片中的表单没有明显的轮廓信息(人类随手拍的),图像文字多为短小、不连续噪音较多,但是笔直的表格线是可以看到的,因此采用检测表格线的方式进行校正。

总体思路:

1、图像预处理

2、用霍夫线变换检测直线

3、对直线做筛选并对角度做统计

4、角度频率最高的直线的角度做为旋转角度返回。(之后就可以根据这个角度进行旋转啦)

代码实现过程中需要注意的点:

1)图像的预处理(根据样本及需求选择预处理方案)

2)霍夫线变换进行检测,调参,了解每个参数的含义

3)直线的角度、弧度的转换

4)选角度均值或是频率最高的值作为最佳旋转角度(选择最优算法策略)

实现代码如下:


//小角度旋转函数
float get_one_small_angle(cv::Mat &img, int max_angle)//传入图像img,倾斜校正允许的最大旋转角度max_angle
{
    cv::Mat m, gray, bi;

    float scale_v = resize_img(img, m);
    m = img.clone();
    //图像预处理(根据需要选择预处理方式)
    cv::cvtColor(m, gray, CV_BGR2GRAY);
    trans_bright(gray);//转换明亮度
    //enhance
    imgEnhanceBrightness(gray);//亮度增强

    int T_length = gray.cols > gray.rows ? gray.rows : gray.cols;
    adaptiveThreshold(gray, bi, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 21, 10);
    medianBlur(bi,bi,3);
    scale_v = resize_img(bi, bi);//二值化

    vector<Vec2f> lines;
    //霍夫线变换检测直线,第五个参数直线的长度阈值,是大于该阈值则认为是一条直线
    HoughLines(bi, lines, 1, CV_PI / 180, 90, 80, 8);

    Mat imtest(bi.rows, bi.cols, CV_8UC3, Scalar(255, 255, 255));//构造一个测试图片
    std::map<int,int> angle_map;
    int cnt = 0;
    int max_cnt = 0;

    float best_angle=0.0;

    int max_iter=300;//检到几十万条线,只取300个,否则循环太慢
    if(lines.size()<300)
        max_iter = lines.size();

    for (size_t i = 0; i < max_iter; i++)
    {
        float rho = lines[i][0];
        float theta = lines[i][1];
        Point pt1, pt2;
        double a = cos(theta), b = sin(theta);
        double x0 = a*rho, y0 = b*rho;
        pt1.x = cvRound(x0 + 1000 * (-b));
        pt1.y = cvRound(y0 + 1000 * (a));
        pt2.x = cvRound(x0 - 1000 * (-b));
        pt2.y = cvRound(y0 - 1000 * (a));
        int length_pt = disPt2Pt(pt1,pt2);
        if(length_pt < (T_length * 0.05)) continue;
        Point pt_mid((pt1.x+pt2.x)/2,(pt1.y+pt2.y)/2);

        //弧度角度注意转换
        float ang_ = atan2((pt2.y-pt1.y)*1.0, (pt2.x-pt1.x)*1.0);
        float theta1 = CV_PI/2 + ang_;
        float fangle = theta1 / CV_PI * 360;
        fangle = round(180 - fangle);//角度四舍五入

        if(abs(fangle)<max_angle && pt_mid.y>bi.rows*0.15 && pt_mid.y < bi.rows*(1-0.15))
        {//直线的角度小于最大倾斜角,且直线既不偏上又不偏下
            cnt++;

            cv::line(imtest, pt1, pt2, Scalar(0,0,0),2);//在imtest上画线

            if(angle_map.end() == angle_map.find(fangle))
            {
                angle_map[fangle] = 1;//map中没有这个角度,则记为1
            }
            else//若角度存在,则+1,并且将频率最高的角度记为最佳角度
            {
                angle_map[fangle]++;
                if(angle_map[fangle]>max_cnt){
                    max_cnt = angle_map[fangle];
                    best_angle = fangle;
                }
            }
        }

//        imshow("linesImg", imtest);
    }

    return best_angle;
}

参考:

OpenCV探索之路(十六):图像矫正技术深入探讨 - Madcola - 博客园

相关文章

网友评论

      本文标题:opencv倾斜校正(C++版)

      本文链接:https://www.haomeiwen.com/subject/feextctx.html