Contour perspective warp

I want to automate a process where text is recognized from a specific card type:

I will first explain what I dit so far. First I converted the image to a grayscale one:

Then I applied Canny:

By the result of this, it was easy to find the largest contour:

So far so good. The problem is: I have a shape here which fits in rectangle. However, the perspective is not top-down. Which implies that it is not possible to use boundingRect. Basically I'm in need of an algorithm to find the orientation of this contour.

I have no idea how to do this. Is there something I am missing? How would you do this?

Edit: Note that the above photo is not a good example, let me add another test case:

edit retag close merge delete

You can use moment to rotate your shape using your largest contour

( 2016-04-02 11:56:59 -0600 )edit

@LBerger How would I do that?

( 2016-04-02 12:01:21 -0600 )edit

you can use Moment or may be minAreaRect

( 2016-04-02 14:27:24 -0600 )edit

@TimK except to the solution from @LBerger you can have a look in this example here, though I think it is more or less based on the concept that @LBerger suggested

( 2016-04-02 17:01:48 -0600 )edit

@theodore That only works on pictures with a top down perspective. I've added a new photo (see edit), to illustrate what I mean and hopefully clear things up! Thanks for you comment.

( 2016-04-03 04:39:38 -0600 )edit

Sort by ยป oldest newest most voted

You need to find first the Homography. Have a look at this tutorial. Then, it would be easier to reverse the usage of scene points and object points to get the transformation that gives you the rectangle in the way you want (instead of finding the orientation of the rectangle in the scene, you try to find the fronto-parallel orientation, if that does make sense).

You could also have a look at the affine transformation estimation made by the estimageRigidTransform function or the findTransformEEC function.

more

May be something like this

int main(int argc, char* argv[])
{
VideoCapture v(0);
Mat img,dst;
double thresh=0;
vector<vector <Point>> ctr;
cvtColor(im,img,CV_BGR2GRAY);
threshold(img,dst,thresh,255,THRESH_OTSU);
findContours(dst,ctr,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);

int idx,maxCtr=-1;
double pi = acos(-1.0);
for (int i = 0; i<ctr.size();i++)
if (saturate_cast<int>(ctr[i].size())>maxCtr)
{
maxCtr=ctr[i].size();
idx=i;
}
RotatedRect r=minAreaRect(ctr[idx]);
cout<<r.center<<"\t Size ="<<r.size<<"\tAngle="<<r.angle<<"\n";
Mat rt1=(Mat_<float>(3,3)<< 1,0,-r.center.x,0,1,-r.center.y,0,0,1);
double theta=(270-r.angle)/180*pi;
Mat rr=(Mat_<float>(3,3)<< cos(theta),-sin(theta),0,sin(theta),cos(theta),0,0,0,1);
Mat rt2=(Mat_<float>(3,3)<< 1,0,r.center.x,0,1,r.center.y,0,0,1);
Mat rAffine;
Mat rt=(rt2*rr*rt1);
rt(Rect(0,0,3,2)).copyTo(rAffine);
Mat imR;
cout<<rAffine;
warpAffine(im, imR,rAffine, im.size());
imshow("result",imR);
waitKey();
return 0;
}


If there is a perpesctive you can use this program. You have to check if point in ctrApprox and rotatedrect are in same order

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/videoio/videoio.hpp"
#include "opencv2/calib3d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/highgui.hpp"

#include <iostream>
#include <fstream>
#include <algorithm>
#include <ctype.h>

using namespace cv;
using namespace std;

int main(int argc, char* argv[])
{
VideoCapture v(0);
Mat img,dst;
double thresh=0;
vector<vector <Point>> ctr;
cvtColor(im,img,CV_BGR2GRAY);
threshold(img,dst,thresh,255,THRESH_OTSU);
findContours(dst,ctr,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);

int idx,maxCtr=-1;
double pi = acos(-1.0);
for (int i = 0; i<ctr.size();i++)
if (saturate_cast<int>(ctr[i].size())>maxCtr)
{
maxCtr=ctr[i].size();
idx=i;
}
vector<Point> ctrApprox;
double epsilon=2;
do
{
approxPolyDP(ctr[idx], ctrApprox, epsilon, true);
epsilon++;
}
while (ctrApprox.size()>4);
RotatedRect r=minAreaRect(ctr[idx]);
vector <Point2f> p2(4);
p2[0] = Point2f(r.center.x - r.size.width/2,r.center.x - r.size.height/2);
p2[1] = Point2f(r.center.x - r.size.width/2,r.center.x + r.size.height/2);
p2[2] = Point2f(r.center.x + r.size.width/2,r.center.x + r.size.height/2);
p2[3] = Point2f(r.center.x + r.size.width/2,r.center.x - r.size.height/2);
Mat rth=findHomography(ctrApprox,p2);
warpPerspective(im, imR,rth, Size(im.size().width*2,im.size().height*2));
imshow("result",imR);
waitKey();
return 0;
}

more