Opencv透视变换——实现不规则四边形转换为规则矩形(以答题卡校正为例)

最近在做答题卡识别方面的工作,但是扫描的答题卡试卷可能会存在一定程度的倾斜,而我们需要提取答题卡有效区域并对其进行校正,实现后续的工作。

倾斜答题卡如下图所示:
这里写图片描述

我们需要对其进行校正:思路如下

  1. 霍夫圆检测
  2. 提取圆心所形成的外包矩形
  3. 利用四个圆心与矩形四角坐标进行校正

1.霍夫圆检测

OpenCV中HoughCircles函数如下:

void HoughCircles(InputArray image,OutputArray circles, int method, double dp, double minDist, double param1=100,double param2=100, int minRadius=0, int maxRadius=0 )

第一个参数:InputArray类型的image,输入图像,即源图像,需为8位的灰度单通道图像。
第二个参数:InputArray类型的circles,经过调用HoughCircles函数后此参数存储了检测到的圆的输出矢量,每个矢量由包含了3个元素的浮点矢量(x, y, radius)表示。
第三个参数:int类型的method,即使用的检测方法,目前OpenCV中就霍夫梯度法一种可以使用,它的标识符为CV_HOUGH_GRADIENT,在此参数处填这个标识符即可。
第四个参数:double类型的dp,用来检测圆心的累加器图像的分辨率于输入图像之比的倒数,且此参数允许创建一个比输入图像分辨率低的累加器。上述文字不好理解的话,来看例子吧。例如,如果dp= 1时,累加器和输入图像具有相同的分辨率。如果dp=2,累加器便有输入图像一半那么大的宽度和高度。
第五个参数:double类型的minDist,为霍夫变换检测到的圆的圆心之间的最小距离,即让我们的算法能明显区分的两个不同圆之间的最小距离。这个参数如果太小的话,多个相邻的圆可能被错误地检测成了一个重合的圆。反之,这个参数设置太大的话,某些圆就不能被检测出来了。
第六个参数:double类型的param1,有默认值100。它是第三个参数method设置的检测方法的对应的参数。对当前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示传递给canny边缘检测算子的高阈值,而低阈值为高阈值的一半。
第七个参数:double类型的param2,也有默认值100。它是第三个参数method设置的检测方法的对应的参数。对当前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示在检测阶段圆心的累加器阈值。它越小的话,就可以检测到更多根本不存在的圆,而它越大的话,能通过检测的圆就更加接近完美的圆形了。
第八个参数:int类型的minRadius,有默认值0,表示圆半径的最小值。
第九个参数:int类型的maxRadius,也有默认值0,表示圆半径的最大值。需要注意的是,使用此函数可以很容易地检测出圆的圆心,但是它可能找不到合适的圆半径
这里写图片描述

2.提取圆心的外包矩形

利用boundingRect函数

//将原因加入一个vector<Point2f>中
obj_corner[0] = Point2f(circles[1][0], circles[1][1]);
obj_corner[1] = Point2f(circles[3][0], circles[3][1]);
obj_corner[2] = Point2f(circles[4][0], circles[4][1]);
obj_corner[3] = Point2f(circles[0][0], circles[0][1]);
//计算其外包矩形
Rect rect = boundingRect(obj_corner);

3.利用四个圆心与矩形四角坐标进行校正

    CvPoint2D32f dst_corner[4], src_corners[4];
    src_corners[0].x = circles[1][0];
    src_corners[0].y = circles[1][1];
    src_corners[1].x = circles[3][0];
    src_corners[1].y = circles[3][1];
    src_corners[2].x = circles[4][0];
    src_corners[2].y = circles[4][1];
    src_corners[3].x = circles[0][0];
    src_corners[3].y = circles[0][1];


    dst_corner[0].x = rect.x;
    dst_corner[0].y = rect.y;
    dst_corner[1].x = rect.x+rect.width;
    dst_corner[1].y = rect.y; 
    dst_corner[2].x = rect.x+rect.width;
    dst_corner[2].y = rect.y+rect.height;
    dst_corner[3].x = rect.x;
    dst_corner[3].y = rect.y+rect.height;
    //计算转换矩阵
    CvMat  *H =cvCreateMat(3, 3, CV_32F);
    cvGetPerspectiveTransform(src_corners, dst_corner, H);
    //对图象进行校正
    IplImage* srcImg = &IplImage(img);
    IplImage* dstImg = cvCloneImage(srcImg);
    cvWarpPerspective(srcImg, dstImg, H, CV_INTER_LINEAR, cvScalarAll(255));

4.结果展示

未校正
这里写图片描述
矫正之后
这里写图片描述

猜你喜欢

转载自blog.csdn.net/weixin_38285131/article/details/81608423