Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perspective correction of imageview

I'm working on an app that needs to apply perspective distortion correction to a photo taken with the phone's camera. Once the photo is taken, the idea is to show it on an imageview and let the user mark the four corners of the document (a card, a sheet of paper, etc.) and then apply the correction based on those points. This is an example of what im trying to achieve:

http://1.bp.blogspot.com/-ro9hniPj52E/TkoM0kTlEnI/AAAAAAAAAbQ/c2R5VrgmC_w/s640/s4.jpg

Any ideas on how to do this on android?

like image 518
Pancho C. Avatar asked Dec 05 '22 16:12

Pancho C.


2 Answers

You don't have to use a library for this. You can just as well use one of the drawBitmap functions of the Canvas class with a matrix that's initialized using the setPolyToPoly function of the Matrix class.

public static Bitmap cornerPin(Bitmap b, float[] srcPoints, float[] dstPoints) {
    int w = b.getWidth(), h = b.getHeight();
    Bitmap result = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
    Canvas c = new Canvas(result);
    Matrix m = new Matrix();
    m.setPolyToPoly(srcPoints, 0, dstPoints, 0, 4);
    c.drawBitmap(b, m, p);
    return result;
}

(The Paint object is only needed to enable anti-aliasing.)

Usage:

int w = bitmap.getWidth(), h = bitmap.getHeight();
float[] src = {
    0, 0, // Coordinate of top left point
    0, h, // Coordinate of bottom left point 
    w, h, // Coordinate of bottom right point
    w, 0  // Coordinate of top right point
};
float[] dst = {
    0, 0,        // Desired coordinate of top left point 
    0, h,        // Desired coordinate of bottom left point  
    w, 0.8f * h, // Desired coordinate of bottom right point
    w, 0.2f * h  // Desired coordinate of top right point
};
Bitmap transformed = cornerPin(bitmap, src, dst);

Where src are the coordinates of the source points, dst are the coordinates of the destination points. Result:

enter image description here

enter image description here

like image 200
Attila Tanyi Avatar answered Dec 07 '22 04:12

Attila Tanyi


What you want to do goes under various names of art, "corner-pin" being the one commonly used in the visual effects industry. You need to proceed in two steps:

  1. Compute the mapping from the the desired, rectified image, to the original, distorted, image
  2. Actually warp the original image according to the mapping computed in (1).

The 4 (non-collinear, perspective-distorted) corners of the original image, and the 4 corners of the target (undistorted) image, define the mapping. This mapping is called a "homography" - read the pointed wikipedia page for details. Once the mapping is known, the warping at step (2) can be computed by interpolation: for every pixel in the target image, find the corresponding pixel in the original image. As this will typically not be at integer coordinates, you interpolate its color from the neighbors. Various interpolation schemes are used, the common ones being nearest-neighbor, bilinear and bicubic (in increasing order of smoothness in the results).

For Android, I'd recommend installing the OpenCV SDK , and then use the geometry transformation routines (getPerspectiveTransform and warpPerspective for the two steps above).

like image 42
Francesco Callari Avatar answered Dec 07 '22 05:12

Francesco Callari