9

I am trying to develop a scanner that can scan a page of a Passport with the camera.

So from a Passport page like this: Sample passport page

I'd like to crop out the marked part.

I have written code for edge detection using OpenCV which finds the contours and then approximates the largest quadrilateral. Finally it does a 4 point perspective transformation to get a top view of the image. The edge detection code look like this:

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;
              }
        }
    }

this code works for single page documents i.e ID cards, credit cards. Where there are 4 distinguishable edges.

But doesn't work for passports as the top edge is not as distinctive.

The inputs will be taken from camera on Android. Any idea how can I detect the passport page? I am using OpenCV 3.1.

Here are a few sample inputs (obtained from Google image search): Sample 1 Sample 2

Mehedi
  • 394
  • 1
  • 3
  • 19
  • Can you provide any information about the conditions of capture: Light condition(especially at the top edge where the direction of light source makes edge darker or disappear), Angle of capture(camera is perpendicular to passport or not), what about the various other country passports(USA has its flag passing from one page to other), the background you will be using? Angle of capture will be difficult as you may not choose to press the passport to be flat on ground(else your hand will occlude the passport). Reason to ask this: Your images are not test images, but picked from google? – saurabheights Nov 10 '16 at 15:56
  • @saurabheights The scanner is supposed to be used on android/ios phones. So the camera quality is supposed to be standard smart phone camera with at least 5 megapixel resolution. Well enough lighting conditions are assumed (no special setup required though). Camera might not exactly be perpendicular to passport but should be close. The background is supposed to be different (darker) than the passport background. Its instrumental that the passport is placed as flat as possible on the ground. Yes the images are taken from google but the solution should work with these as a base test case. – Mehedi Nov 11 '16 at 04:01
  • I do have some initial thoughts such as use of Canny & Hough, accompanied with fitting to dimension of passport. Consider vertical/near-vertical lines from Hough Transform and do same for Horizontal. A perspective transform of horizontal edge and vertical edge should get you a rectangular image. The dimension will help in issues from top edge of passport. A final poly-fit should do the final task. Color segmentation between background and passport(light-colored & usually in center) may also be helpful, but with variation between passports from various countries, it could be error-prone. – saurabheights Nov 11 '16 at 18:59

1 Answers1

7

It would be possible to extract the page if you can locate the Machine Readable Zone (MRZ) of the passport (region outlined in red in the image below). Usually, there's a very good contrast between the MRZ and its background, so it can be detected using a gradient based method or MSERs.

Assuming there's a standard template (that is, aspect ratios for the page, the MRZ, offsets for the fields, etc.) according to which the passport is prepared, once you locate the MRZ, it's easy to locate the page borders and other fields such as the photo of the person as shown in the template image below where the MRZ is outlined in red and the page border is outlined in green. This is assuming there's no perspective distortion. If there's such distortion, first you should correct it and then apply the template. You can use the MRZ itself to correct the distortion as you know the aspect ratio of the MRZ region.

Template prepared from image.

template

Check here for a very simple implementation of this template model based field extraction from a passport. It won't work for your images, and will need lots of parameter tuning, so I don't recommend using it straight away. I'm referring it just to convey the idea of template-based extraction and other pre-processing methods.

However, if the passport is curved as in the image below (you can see the MRZ boundary cannot be traced using straight lines), it is difficult to correct the distortion.

Finally, if you are using high resolution images, it would be a good idea to downsample and process them as it would be faster on an embedded system. Once you locate the MRZ from downsampled image, you can use the high-res image to refine the corners. mrz

Community
  • 1
  • 1
dhanushka
  • 10,492
  • 2
  • 37
  • 47
  • I have pursued the idea of detecting the MRZ, but as there are distortions I am having trouble to get a top view of the passport page, doing a perspective transformation with the rectangle I approximated from the aspect ratio of the page doesn't yield very good results. – Mehedi Dec 27 '16 at 14:52
  • @Mehedi Do you mean that you are able to correctly detect the bounds of the MRZ, but the MRZ is not subjected to a perspective distortion, or though the distortion is perspective, the error you make in detecting the page bounds is high? – dhanushka Dec 27 '16 at 15:52
  • I can detect the MRZ bounds, but as you see the image is curved (has a rotated perspective), if I take the bounding rect of the MRZ contour and calculate the page bound as a rect from that, the image I get doesn't contain the whole page as it is. Is there a way to warp the perspective to get a top view of the page using the MRZ quadrilateral/contour? – Mehedi Dec 28 '16 at 09:11
  • @Mehedi You can find the projection matrix by matching the four corners of the MRZ quadrilateral in image to the MRZ rectangle in your template. Then you can use it to correct the perspective. – dhanushka Dec 28 '16 at 10:58
  • @Mehedi check [getperspectivetransform](http://docs.opencv.org/2.4/modules/imgproc/doc/geometric_transformations.html#getperspectivetransform) – dhanushka Dec 28 '16 at 11:11
  • can you please have a [look at this](http://stackoverflow.com/questions/41398356/how-to-scale-a-contours-height-by-a-factor) – Mehedi Dec 30 '16 at 15:09
  • @Mehedi As I said earlier, you should find the four corners of the MRZ quadrilateral and then match those to the four corners of the MRZ rectangle of your template. Now you have 4 matching points for the getperspectivetransform to calculate the homography. However, establishing the point correspondence is a bit tricky. I'll try it out when I get some free time, and will update the post if I make good progress. – dhanushka Dec 31 '16 at 15:54