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.结果展示

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

  • 7
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以使用 OpenCV 库中的函数来实现这个功能。首先,你需要读取图像并显示它。然后,你可以使用鼠标事件来选择四边形的顶点。一旦你选择了四个顶点,你可以使用透视变换校正图像。以下是一个示例代码: ```python import cv2 import numpy as np # 读取图像 img = cv2.imread('image.jpg') # 显示图像 cv2.imshow('Original Image', img) # 定义鼠标事件回调函数 def select_points(event, x, y, flags, params): # 如果鼠标左键按下 if event == cv2.EVENT_LBUTTONDOWN: # 将当前点添加到顶点列表中 pts.append((x, y)) # 在图像上绘制一个圆圈表示当前点 cv2.circle(img, (x, y), 5, (0, 0, 255), -1) # 如果已经选择了四个顶点 if len(pts) == 4: # 定义透视变换的源点和目标点 src = np.float32(pts) dst = np.float32([[0, 0], [500, 0], [500, 500], [0, 500]]) # 计算透视变换矩阵 M = cv2.getPerspectiveTransform(src, dst) # 应用透视变换 warped = cv2.warpPerspective(img, M, (500, 500)) # 显示校正后的图像 cv2.imshow('Warped Image', warped) # 创建一个空的顶点列表 pts = [] # 注册鼠标事件回调函数 cv2.setMouseCallback('Original Image', select_points) # 等待用户按下 ESC 键退出程序 while True: if cv2.waitKey(0) == 27: break # 关闭所有窗口 cv2.destroyAllWindows() ``` 在这个示例代码中,我们首先读取图像并显示它。然后,我们定义一个鼠标事件回调函数,该函数会在用户选择四个顶点时被调用。在回调函数中,我们将当前点添加到顶点列表中,并在图像上绘制一个圆圈表示当前点。如果已经选择了四个顶点,我们就计算透视变换矩阵并应用它来校正图像。最后,我们显示校正后的图像,并等待用户按下 ESC 键退出程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值