15

I'm working on a app where I'll let the user take a picture e.g of a business card or photograph.

The user will then mark the four corners of the object (which they took a picture off) - Like it is seen in a lot of document/image/business card scanning apps:

enter image description here

My question is how do i crop and fix the perspective according to these four points? I've been searching for days and looked at several image proccessing libraries without any luck.

Any one who can point me in the right direction?

Stephen Kennedy
  • 20,585
  • 22
  • 95
  • 108
Jakob Halskov
  • 428
  • 6
  • 22
  • Here is an other way to achieve this: http://stackoverflow.com/questions/9470493/transforming-a-rectangle-image-into-a-quadrilateral-using-a-catransform3d Let me know if this helps. – MonsieurDart Mar 27 '12 at 08:31
  • Hi, Are you getting the solution? Kindly can you post the code of this problem. I need exact like this. – Mani Sep 18 '13 at 13:05
  • @mani I never found a good solution to this. Unfortunately. – Jakob Halskov Sep 20 '13 at 14:14

4 Answers4

9

From iOS8+ there is Filter for Core Image called CIPerspectiveCorrection. All you need to do is pass the image and four points.Perspective Correction

Also there is one more filter supporting iOS6+ called CIPerspectiveTransform which can be used in similar way (skewing image).

Roman Roba
  • 405
  • 5
  • 11
1

I'm not sure if you've tried the Opencv library yet, but it has a very nice way to deskew an image. I've got here a small snippet that takes an array of corners, your four corners for example, and a final size to map it into.

You can read the man page for warpPerspective on the OpenCV site.

cv::Mat deskew(cv::Mat& capturedFrame, cv::Point2f source_points[], cv::Size finalSize)
{
    cv::Point2f dest_points[4];

    // Output of deskew operation has same color space as source frame, but
    // is proportional to the area the document occupied; this is to reduce
    // blur effects from a scaling component.
    cv::Mat deskewedMat = cv::Mat(finalSize, capturedFrame.type());

    cv::Size s = capturedFrame.size();

    // Deskew to full output image corners
    dest_points[0] = cv::Point2f(0,s.height); // lower left
    dest_points[1] = cv::Point2f(0,0);        // upper left
    dest_points[2] = cv::Point2f(s.width,0);  // upper right
    dest_points[3] = cv::Point2f(s.width,s.height);  // lower right

    // Build quandrangle "de-skew" transform matrix values
    cv::Mat transform = cv::getPerspectiveTransform( source_points, dest_points  );
    // Apply the deskew transform
    cv::warpPerspective( capturedFrame, deskewedMat, transform, s, cv::INTER_CUBIC );

    return deskewedMat;
}
Buddhisthead
  • 329
  • 2
  • 12
1

If this image were loaded in as a texture, it'd be extremely simple to skew it using OpenGL. You'd literally just draw a full-screen quad and use the yellow correction points as the UV coordinate at each point.

StilesCrisis
  • 15,972
  • 4
  • 39
  • 62
  • 2
    The texture on rectangle will be distorted so diagonal will be seen. To map "in-perspective" rect correctly we need to dial with texture z-coordinate. – brigadir Jan 30 '12 at 07:38
  • At these sorts of shallow angles, I wouldn't expect that it would matter too much. But if it's super important to get that right, it's still easy with OpenGL. Just draw the image as a quad (with the UV coordinates left alone this time), but instead of pointing the camera head-on at it, adjust the camera position slightly to compensate for the skew of the original picture. Now the only challenge is figuring out where to place the camera. – StilesCrisis Jan 30 '12 at 09:16
  • The only problem with that solution is that anyone looking to do perspective correction would want to save the image at the full original resolution (or as close to it as possible given the natural cropping put in by the control points). So in this case, you'd be displaying the perspective corrected image nicely on the screen, but would it be possible to save it to disk? – Joel Martinez Jan 31 '12 at 14:10
  • Thanks for your suggestions - It sounds like a good solution! My problem is now how to 'do' and implement this. I have a basic understanding of OpenGL ES, but I'm not sure how to draw the image as a quad. – Jakob Halskov Jan 31 '12 at 18:48
  • Drawing a quad is about the simplest possible thing you can do. You just draw a flat rectangle using two triangles. – StilesCrisis Jan 31 '12 at 20:05
0

I don't know exact solution of your case, but there is approach for trapezoid: http://www.comp.nus.edu.sg/~tants/tsm/TSM_recipe.html - the idea is to continuously build transformation matrix. Theoretically you can add transformation that converts your shape into trapecy.

And there are many questions like this: https://math.stackexchange.com/questions/13404/mapping-irregular-quadrilateral-to-a-rectangle , but I didn't check solutions.

Community
  • 1
  • 1
brigadir
  • 6,874
  • 6
  • 46
  • 81
  • Also check this question with answer: http://stackoverflow.com/questions/9088882/return-catransform3d-to-map-quadrilateral-to-quadrilateral – brigadir Feb 01 '12 at 07:24