2016-10-22 42 views
8

我正在嘗試開發一種可以用相機掃描護照頁面的掃描儀。如何使用OpenCV檢測Passport頁面的界限?

所以從護照頁是這樣的: Sample passport page

我想裁掉的標記部分。

我已經編寫了使用OpenCV進行邊緣檢測的代碼,它可以找到輪廓,然後近似最大的四邊形。最後,它進行4點透視轉換以獲得圖像的頂視圖。邊緣檢測代碼如下所示:

public static List<MatOfPoint> findContours(Mat src){ 
    Mat img = src.clone(); 
    src.release(); 
    //find contours 
    double ratio = getScaleRatio(img.size()); 
    int width = (int) (img.size().width/ratio); 
    int height = (int) (img.size().height/ratio); 
    Size newSize = new Size(width, height); 
    Mat resizedImg = new Mat(newSize, CvType.CV_8UC4); 
    Imgproc.resize(img, resizedImg, newSize); 

    Imgproc.medianBlur(resizedImg, resizedImg, 5); 

    Mat cannedImg = new Mat(newSize, CvType.CV_8UC1); 
    Imgproc.Canny(resizedImg, cannedImg, 70, 200, 3, true); 
    resizedImg.release(); 

    Imgproc.threshold(cannedImg, cannedImg, 200, 255, Imgproc.THRESH_OTSU); 

    Mat dilatedImg = new Mat(newSize, CvType.CV_8UC1); 
    Mat morph = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3, 3)); 
    Imgproc.dilate(cannedImg, dilatedImg, morph, new Point(-1, -1), 2, 1, new Scalar(1)); 
    cannedImg.release(); 
    morph.release(); 

    ArrayList<MatOfPoint> contours = new ArrayList<>(); 
    Mat hierarchy = new Mat(); 
    Imgproc.findContours(dilatedImg, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE); 
    hierarchy.release(); 

    Log.d(TAG, "contours found: " + contours.size()); 

    Collections.sort(contours, new Comparator<MatOfPoint>() { 
     @Override 
     public int compare(MatOfPoint o1, MatOfPoint o2) { 
      return Double.valueOf(Imgproc.contourArea(o2)).compareTo(Imgproc.contourArea(o1)); 
     } 
    }); 

    return contours; 
} 

for(MatOfPoint contour:contours){ 
     MatOfPoint2f mat = new MatOfPoint2f(contour.toArray()); 
     double peri = Imgproc.arcLength(mat, true); 
     MatOfPoint2f approx = new MatOfPoint2f(); 
     Imgproc.approxPolyDP(mat, approx, 0.02 * peri, true); 

     Point[] points = approx.toArray(); 
     Log.d("SCANNER", "approx size " + points.length); 

     if (points.length == 4) { 
       Point[] spoints = CVProcessor.sortPoints(points); 

       if (CVProcessor.insideArea(spoints, newSize)) { 
         rectContour = contour; 
         foundPoints = spoints; 
         break; 
       } 
     } 
    } 

此代碼適用於單頁文檔,即ID卡,信用卡。哪裏有4個可區分的邊緣。

但不適用於護照,因爲最高優勢不如其獨特。

輸入將從Android上的相機拍攝。任何想法如何檢測護照頁面?我正在使用OpenCV 3.1。

這裏是(從谷歌圖像搜索獲得的)幾個採樣輸入: Sample 1 Sample 2

+0

您能否提供有關拍攝條件的任何信息:光線條件(特別是在光源方向變得更暗或消失的頂部邊緣),拍攝角度(相機與護照是否垂直),那麼各種其他國家的護照(美國的旗幟從一頁傳到另一頁)呢,你將使用的背景是什麼?捕獲角度將很困難,因爲您可能不會選擇將護照平放在地面上(否則您的手會擋住護照)。請問這個問題的理由:您的圖片不是測試圖片,而是從谷歌中挑選出來的? – saurabheights

+0

@saurabheights掃描儀應該在android/ios手機上使用。所以相機質量應該是標準智能手機相機至少500萬像素的分辨率。假設照明條件足夠好(不需要特別設置)。相機可能不完全垂直於護照,但應該靠近。背景應該與護照背景不同(較深)。它的作用是將護照儘可能平放在地面上。是的,圖片是從谷歌採取的,但解決方案應該與這些作爲基礎測試案例。 – Mehedi

+0

我的確有一些初步的想法,比如使用Canny&Hough,並配以護照尺寸。考慮Hough變換中的垂直/接近垂直線,並對水平線做同樣的處理。水平邊緣和垂直邊緣的透視變換應該爲你提供一個矩形圖像。這個維度將有助於從護照頂端的問題。最後的聚合應該做最後的任務。背景和護照之間的顏色分割(淺色和通常居中)也可能有所幫助,但由於各個國家的護照之間存在差異,因此可能會出現錯誤。 – saurabheights

回答

5

這將是可以提取的頁面,如果你能找到護照(區的Machine Readable Zone (MRZ)在紅色邊框圖像如下)。通常,MRZ與其背景之間存在非常好的對比,所以可以使用基於梯度的方法或MSER s來檢測。

假設有一張準備護照的標準模板(即頁面長寬比,MRZ,字段偏移量等),一旦找到MRZ,就很容易找到頁面邊框和其他字段,例如下圖所示的模板圖像中顯示的人物照片,其中MRZ以紅色框出,而頁面邊框以綠色框出。這是假設沒有透視失真。如果有這樣的失真,首先你應該糾正它,然後應用模板。如果您知道MRZ區域的寬高比,則可以使用MRZ本身來校正失真。

模板從image準備。

template

檢查here一個非常簡單的實現從一本護照本模板模型基於現場提取的。它不適合你的圖像,並且需要大量的參數調整,所以我不建議馬上使用它。我只是想傳達一下基於模板的提取和其他預處理方法的想法。

但是,如果護照如下圖所示彎曲(可以看到MRZ邊界不能用直線進行追蹤),則很難糾正失真。

最後,如果您使用的是高分辨率圖像,那麼對它們進行縮減採樣和處理將是一個不錯的主意,因爲在嵌入式系統上它會更快。一旦您從縮減採樣圖像中找到MRZ,您可以使用高分辨率圖像來優化角點。 mrz

+0

我一直在追尋檢測MRZ的想法,但由於存在扭曲,我無法獲得護照頁面的頂視圖,因此使用從頁面長寬比近似得出的矩形做透視變換不會產生屈服非常好的結果。 – Mehedi

+0

@Mehedi您的意思是說您能夠正確檢測MRZ的邊界,但是MRZ不會受到透視失真,或者失真是透視,您在檢測頁面邊界時所犯的錯誤很高? – dhanushka

+0

我可以檢測到MRZ界限,但是當您看到圖像是彎曲的(具有旋轉的透視圖)時,如果我採用MRZ輪廓的邊界矩形並從中計算頁面邊界作爲矩形,則得到的圖像不會「 t包含整個頁面。是否有辦法使用MRZ四邊形/輪廓來查看頁面的頂視圖? – Mehedi