package gab.opencv; import java.util.ArrayList; import processing.core.*; import org.opencv.core.MatOfPoint; import org.opencv.core.MatOfPoint2f; import org.opencv.imgproc.Imgproc; import org.opencv.core.Rect; import org.opencv.core.Mat; import org.opencv.core.MatOfInt; import org.opencv.core.Point; import java.awt.Rectangle; public class Contour { private ArrayList points; private Point[] inputPoints; private double polygonApproximationFactor; private PApplet parent; private Rectangle boundingBox; public MatOfPoint pointMat; public Contour(PApplet parent, MatOfPoint mat){ polygonApproximationFactor = mat.size().height * 0.01; this.parent = parent; this.pointMat = mat; Rect r = Imgproc.boundingRect(mat); boundingBox = new Rectangle(r.x, r.y, r.width, r.height); loadPoints(mat.toArray()); } public Contour(PApplet parent, MatOfPoint2f mat){ polygonApproximationFactor = mat.size().height * 0.01; this.parent = parent; this.pointMat = new MatOfPoint(mat.toArray()); Rect r = Imgproc.minAreaRect(mat).boundingRect(); boundingBox = new Rectangle(r.x, r.y, r.width, r.height); loadPoints(mat.toArray()); } public void loadPoints(Point[] pts){ points = new ArrayList(); inputPoints = pts; for(int i = 0; i < inputPoints.length; i++){ points.add(new PVector((float)inputPoints[i].x, (float)inputPoints[i].y)); } } /** * Check if the Contour contains a given x-y point. * Particularly, useful for interaction via mouseX and mouseY. * * @param x * @param y * @return boolean */ public boolean containsPoint(int x, int y){ Point p = new Point(x,y); MatOfPoint2f m = new MatOfPoint2f(pointMat.toArray()); double r = Imgproc.pointPolygonTest(m,p, false); return r == 1; } /** * The polygonApproximationFactor is used to determine * how strictly to follow a curvy polygon when converting * it into a simpler polygon with getPolygonApproximation(). * For advanced use only. Set to a sane value by default. * * @param polygonApproximationFactor, a double */ public void setPolygonApproximationFactor(double polygonApproximationFactor){ this.polygonApproximationFactor = polygonApproximationFactor; } /** * Access the current polygonApproximationFactor. The polygonApproximationFactor * is used to determine how strictly to follow a curvy polygon when converting * it into a simpler polygon with getPolygonApproximation(). * * @return polygonApproximationFactor, a double */ public double getPolygonApproximationFactor(){ return polygonApproximationFactor; } /** * Get a new Contour that results from calculating * the polygon approximation of the current Contour. * The tightness of the approximation is set by the polygonApproximationFactor, * See setPolygonApproximationFactor() and getPolygonApproximationFactor(). * * @return */ public Contour getPolygonApproximation(){ MatOfPoint2f approx = new MatOfPoint2f(); Imgproc.approxPolyDP(new MatOfPoint2f(inputPoints), approx, polygonApproximationFactor, true); return new Contour(parent, approx); } /** * Calculate a convex hull from the current Contour. * Returns a new Contour representing the convex hull. * * @return Contour */ public Contour getConvexHull(){ MatOfInt hull = new MatOfInt(); MatOfPoint points = new MatOfPoint(pointMat); Imgproc.convexHull(points, hull); Point[] hp = new Point[hull.height()]; for(int i = 0; i < hull.height(); i++){ int index = (int)hull.get(i,0)[0]; hp[i] = new Point(pointMat.get(index,0)); } MatOfPoint hullPoints = new MatOfPoint(); hullPoints.fromArray(hp); return new Contour(parent, hullPoints); } /** * Draw the Contour as a closed shape with one vertex per-point. * */ public void draw(){ parent.beginShape(); for (PVector p : points) { parent.vertex(p.x, p.y); } parent.endShape(PConstants.CLOSE); } /** * Get the points that make up the Contour. * * @return ArrayList points */ public ArrayList getPoints(){ return points; } /** * The number of points in the Contour. * * @return int */ public int numPoints(){ return points.size(); } /** * Get the bounding box for the Contour. * * @return A java.awt.Rectangle */ public Rectangle getBoundingBox(){ return boundingBox; } /** * The area of the Contour's bounding box. In most cases, this is a good approximation for the Contour's area. * * @return float area */ public float area(){ return (boundingBox.width * boundingBox.height); } }