OpenCV倾斜图片校正(情况一:背景与前景差别较大,情况二:倾斜文本)

原文地址:https://www.cnblogs.com/skyfsm/p/6902524.html
情况一:背景与前景差别较大
一,效果图
这里写图片描述
这里写图片描述

二,代码

//第一个参数:输入图片名称;第二个参数:输出图片名称
void GetContoursPic(const char* pSrcFileName, const char* pDstFileName)
{
    Mat srcImg = imread(pSrcFileName);
    imshow("原始图", srcImg);
    Mat gray, binImg;
    //灰度化
    cvtColor(srcImg, gray, COLOR_RGB2GRAY);
    //imshow("灰度图", gray);
    //二值化
    threshold(gray, binImg, 100, 255, CV_THRESH_BINARY);
    imshow("二值化", binImg);

    vector<vector<Point> > contours;
    vector<Rect> boundRect(contours.size());
    //注意第5个参数为CV_RETR_EXTERNAL,只检索外框  
    findContours(binImg, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); //找轮廓
    cout << contours.size() << endl;
    for (int i = 0; i < contours.size(); i++)
    {
        //需要获取的坐标  
        CvPoint2D32f rectpoint[4];
        CvBox2D rect = minAreaRect(Mat(contours[i]));

        cvBoxPoints(rect, rectpoint); //获取4个顶点坐标  
        //与水平线的角度  
        float angle = rect.angle;
        cout << angle << endl;

        int line1 = sqrt((rectpoint[1].y - rectpoint[0].y)*(rectpoint[1].y - rectpoint[0].y) + (rectpoint[1].x - rectpoint[0].x)*(rectpoint[1].x - rectpoint[0].x));
        int line2 = sqrt((rectpoint[3].y - rectpoint[0].y)*(rectpoint[3].y - rectpoint[0].y) + (rectpoint[3].x - rectpoint[0].x)*(rectpoint[3].x - rectpoint[0].x));
        //rectangle(binImg, rectpoint[0], rectpoint[3], Scalar(255), 2);
        //面积太小的直接pass
        if (line1 * line2 < 600)
        {
            continue;
        }

        //为了让正方形横着放,所以旋转角度是不一样的。竖放的,给他加90度,翻过来  
        if (line1 > line2)
        {
            angle = 90 + angle;
        }

        //新建一个感兴趣的区域图,大小跟原图一样大  
        Mat RoiSrcImg(srcImg.rows, srcImg.cols, CV_8UC3); //注意这里必须选CV_8UC3
        RoiSrcImg.setTo(0); //颜色都设置为黑色  
        //imshow("新建的ROI", RoiSrcImg);
        //对得到的轮廓填充一下  
        drawContours(binImg, contours, -1, Scalar(255), CV_FILLED);

        //抠图到RoiSrcImg
        srcImg.copyTo(RoiSrcImg, binImg);


        //再显示一下看看,除了感兴趣的区域,其他部分都是黑色的了  
        //namedWindow("RoiSrcImg", 1);
        //imshow("RoiSrcImg", RoiSrcImg);

        //创建一个旋转后的图像  
        Mat RatationedImg(RoiSrcImg.rows, RoiSrcImg.cols, CV_8UC1);
        RatationedImg.setTo(0);
        //对RoiSrcImg进行旋转  
        Point2f center = rect.center;  //中心点  
        Mat M2 = getRotationMatrix2D(center, angle, 1);//计算旋转加缩放的变换矩阵 
        warpAffine(RoiSrcImg, RatationedImg, M2, RoiSrcImg.size(), 1, 0, Scalar(0));//仿射变换 
        //imshow("旋转之后", RatationedImg);
        //imwrite("r.jpg", RatationedImg); //将矫正后的图片保存下来
    }

#if 1
    //对ROI区域进行抠图

    //对旋转后的图片进行轮廓提取  
    vector<vector<Point> > contours2;
    Mat raw = imread("r.jpg");
    Mat SecondFindImg;
    //SecondFindImg.setTo(0);
    cvtColor(raw, SecondFindImg, COLOR_BGR2GRAY);  //灰度化  
    threshold(SecondFindImg, SecondFindImg, 80, 200, CV_THRESH_BINARY);
    findContours(SecondFindImg, contours2, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
    //cout << "sec contour:" << contours2.size() << endl;

    for (int j = 0; j < contours2.size(); j++)
    {
        //这时候其实就是一个长方形了,所以获取rect  
        Rect rect = boundingRect(Mat(contours2[j]));
        //面积太小的轮廓直接pass,通过设置过滤面积大小,可以保证只拿到外框
        if (rect.area() < 600)
        {
            continue;
        }
        Mat dstImg = raw(rect);
        imshow("dst", dstImg);
        imwrite(pDstFileName, dstImg);
    }
#endif


}

//测试
void CCutImageVS2013Dlg::OnBnClickedTestButton1()
{
    GetContoursPic("D:\\测试图片\\book.jpg", "FinalImage.jpg");
    waitKey();
}

情况二:倾斜文本
一,效果图
这里写图片描述
这里写图片描述

二,源代码

#define ERROR 1234

//度数转换
double DegreeTrans(double theta)
{
    double res = theta / CV_PI * 180;
    return res;
}


//逆时针旋转图像degree角度(原尺寸)    
void rotateImage(Mat src, Mat& img_rotate, double degree)
{
    //旋转中心为图像中心    
    Point2f center;
    center.x = float(src.cols / 2.0);
    center.y = float(src.rows / 2.0);
    int length = 0;
    length = sqrt(src.cols*src.cols + src.rows*src.rows);
    //计算二维旋转的仿射变换矩阵  
    Mat M = getRotationMatrix2D(center, degree, 1);
    warpAffine(src, img_rotate, M, Size(length, length), 1, 0, Scalar(255, 255, 255));//仿射变换,背景色填充为白色  
}

//通过霍夫变换计算角度
double CalcDegree(const Mat &srcImage, Mat &dst)
{
    Mat midImage, dstImage;

    Canny(srcImage, midImage, 50, 200, 3);
    cvtColor(midImage, dstImage, CV_GRAY2BGR);

    //通过霍夫变换检测直线
    vector<Vec2f> lines;
    HoughLines(midImage, lines, 1, CV_PI / 180, 300, 0, 0);//第5个参数就是阈值,阈值越大,检测精度越高
    //cout << lines.size() << endl;

    //由于图像不同,阈值不好设定,因为阈值设定过高导致无法检测直线,阈值过低直线太多,速度很慢
    //所以根据阈值由大到小设置了三个阈值,如果经过大量试验后,可以固定一个适合的阈值。

    if (!lines.size())
    {
        HoughLines(midImage, lines, 1, CV_PI / 180, 200, 0, 0);
    }
    //cout << lines.size() << endl;

    if (!lines.size())
    {
        HoughLines(midImage, lines, 1, CV_PI / 180, 150, 0, 0);
    }
    //cout << lines.size() << endl;
    if (!lines.size())
    {
        cout << "没有检测到直线!" << endl;
        return ERROR;
    }

    float sum = 0;
    //依次画出每条线段
    for (size_t i = 0; i < lines.size(); i++)
    {
        float rho = lines[i][0];
        float theta = lines[i][1];
        Point pt1, pt2;
        //cout << theta << endl;
        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));
        //只选角度最小的作为旋转角度
        sum += theta;

        line(dstImage, pt1, pt2, Scalar(55, 100, 195), 1); //Scalar函数用于调节线段颜色

        imshow("直线探测效果图", dstImage);
    }
    float average = sum / lines.size(); //对所有角度求平均,这样做旋转效果会更好

    cout << "average theta:" << average << endl;

    double angle = DegreeTrans(average) - 90;

    rotateImage(dstImage, dst, angle);
    //imshow("直线探测效果图2", dstImage);
    return angle;
}


void ImageRecify(const char* pInFileName, const char* pOutFileName)
{
    double degree;
    Mat src = imread(pInFileName);
    imshow("原始图", src);
    Mat dst;
    //倾斜角度矫正
    degree = CalcDegree(src, dst);
    if (degree == ERROR)
    {
        cout << "矫正失败!" << endl;
        return;
    }
    rotateImage(src, dst, degree);
    cout << "angle:" << degree << endl;
    imshow("旋转调整后", dst);

    Mat resulyImage = dst(Rect(0, 0, dst.cols, 500)); //根据先验知识,估计好文本的长宽,再裁剪下来
    imshow("裁剪之后", resulyImage);
    imwrite("recified.jpg", resulyImage);
}


//测试
void CCutImageVS2013Dlg::OnBnClickedTestButton1()
{
    ImageRecify("D:\\测试图片\\倾斜文本.png", "FinalImage.jpg");
    waitKey();
    return ;
}
//===============================================================================================

猜你喜欢

转载自blog.csdn.net/sxlsxl119/article/details/80882965