2016-10-22 38 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