I am trying to detect a card and do warpperspective on the image. I have successfully get the contour of the card. But I am facing difficulties on how to get the vertices point (show as blue point in image) as the input of getPerspectiveTransform function. Actually I have done it with simple algorithm on a static image. However, it does not work well for live frame especially when the card rotate. Is there any simple yet robust method that can get the four vertices point of card regardless of the orientation of card?
MatOfPoint2f curve = new MatOfPoint2f(matched.toArray());
double perimeter = Imgproc.arcLength(curve, true);
MatOfPoint2f approxCurve2f = new MatOfPoint2f();
Imgproc.approxPolyDP(curve, approxCurve2f, 0.003 * perimeter, true);
Mat temp = new Mat(src.rows(),src.cols(),CvType.CV_8UC1);
Imgproc.drawContours(temp, cnt, -1, new Scalar(255,255,255));
Moments moment = Imgproc.moments(matched);
Point centroid = new Point(moment.m10/moment.m00, moment.m01/moment.m00);
MatOfPoint approxCurve = new MatOfPoint();
approxCurve2f.convertTo(approxCurve, CvType.CV_32S);
List<Point> corners = Util.toPointList(approxCurve);
//group points that near each other
List<List<Point>> grouping = Util.cornerPointGrouping(corners, 50);
if(grouping.size()!=4)
{
return temp;
}
Mat before = new Mat(1,4, CvType.CV_32FC2);
Mat after = new Mat(1,4, CvType.CV_32FC2);
Util.generateTransformationParams(grouping, centroid, before, after);
Mat transformMat = Imgproc.getPerspectiveTransform(before, after);
Mat out = new Mat();
Size dsize = new Size(src.width(), src.height());
Imgproc.warpPerspective(src, out, transformMat, dsize);
public static void generateTransformationParams(List<List<Point>> grouping,
Point centroid, Mat before, Mat after)
{
Point topLeft=new Point(), topRight=new Point(),
btmLeft=new Point(), btmRight=new Point();
for(List<Point> list: grouping)
{
List<Point> ySorted = new ArrayList<>(list);
Collections.sort(list, new xComparator());
Collections.sort(ySorted, new yComparator());
if(list.get(0).y<centroid.y) //top
{
if(list.get(0).x<centroid.x) //left
{
topLeft = new Point(list.get(0).x,ySorted.get(0).y);
}
else //right
{
topRight = new Point(list.get(list.size()-1).x,ySorted.get(0).y);
}
}
else //bottom
{
if(list.get(0).x<centroid.x) //left
{
btmLeft = new Point(list.get(0).x,ySorted.get(list.size()-1).y);
}
else //right
{
btmRight = new Point(list.get(list.size()-1).x,ySorted.get(list.size()-1).y);
}
}
}
//btmLeft as reference
before.put(0, 0, topLeft.x, topLeft.y, topRight.x, topRight.y,
btmRight.x, btmRight.y, btmLeft.x, btmLeft.y);
double width = Util.getLength(btmLeft, btmRight);
double height = width/creditCardRatio;
after.put(0, 0, btmLeft.x, btmLeft.y-height, btmLeft.x+width, btmLeft.y-height,
btmLeft.x+width, btmLeft.y, btmLeft.x, btmLeft.y);
}
I tried minAreaRect and it works well when the card is rectangle. When the perspective change, it fails to give me the accurate vertices.