美文网首页
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