1. 程式人生 > >Opencv透視變換——實現不規則四邊形轉換為規則矩形(以答題卡校正為例)

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

未校正
這裡寫圖片描述
矯正之後
這裡寫圖片描述