In the Grip generated pipeline code, I want to sort the list of filtered contours to locate the best matches…
Assuming for the moment that I wanted to use area, can anyone show me a code snipit that I can add to the filterContours() method to sort the output array…
Seems like I need to use the Collections.sort() method but I can’t get it to accept my arguments.
/**
* Filters out contours that do not meet certain criteria.
* @param inputContours is the input list of contours
* @param output is the the output list of contours
* @param minArea is the minimum area of a contour that will be kept
* @param minPerimeter is the minimum perimeter of a contour that will be kept
* @param minWidth minimum width of a contour
* @param maxWidth maximum width
* @param minHeight minimum height
* @param maxHeight maximimum height
* @param Solidity the minimum and maximum solidity of a contour
* @param minVertexCount minimum vertex Count of the contours
* @param maxVertexCount maximum vertex Count
* @param minRatio minimum ratio of width to height
* @param maxRatio maximum ratio of width to height
*/
private void filterContours(List<MatOfPoint> inputContours, double minArea,
double minPerimeter, double minWidth, double maxWidth, double minHeight, double
maxHeight, double] solidity, double maxVertexCount, double minVertexCount, double
minRatio, double maxRatio, List<MatOfPoint> output) {
final MatOfInt hull = new MatOfInt();
output.clear();
//operation
for (int i = 0; i < inputContours.size(); i++) {
final MatOfPoint contour = inputContours.get(i);
final Rect bb = Imgproc.boundingRect(contour);
if (bb.width < minWidth || bb.width > maxWidth) continue;
if (bb.height < minHeight || bb.height > maxHeight) continue;
final double area = Imgproc.contourArea(contour);
if (area < minArea) continue;
if (Imgproc.arcLength(new MatOfPoint2f(contour.toArray()), true) < minPerimeter) continue;
Imgproc.convexHull(contour, hull);
// Add new huul
MatOfPoint mopHull = new MatOfPoint();
mopHull.create((int) hull.size().height, 1, CvType.CV_32SC2);
for (int j = 0; j < hull.size().height; j++) {
int index = (int)hull.get(j, 0)[0];
double] point = new double] { contour.get(index, 0)[0], contour.get(index, 0)[1]};
mopHull.put(j, 0, point);
}
final double solid = 100 * area / Imgproc.contourArea(mopHull);
if (solid < solidity[0] || solid > solidity[1]) continue;
if (contour.rows() < minVertexCount || contour.rows() > maxVertexCount) continue;
final double ratio = bb.width / (double)bb.height;
if (ratio < minRatio || ratio > maxRatio) continue;
// Add to main output list
output.add(contour);
}
}
When sorting objects with the Collections.sort() method, you will typically want to supply the “comparator” parameter that lets you control the comparison between each object (decide which should come before the other).
For example, if you want to sort by area, I think you can use a static helper method something like the following:
public static void sortContoursByArea(List<MatOfPoint> contours) {
Collections.sort(contours, new Comparator<MatOfPoint>() {
@Override
public int compare(MatOfPoint a, MatOfPoint b) {
// Not sure how expensive this will be computationally as the
// area is computed for each comparison
double areaA = Imgproc.contourArea(a);
double areaB = Imgproc.contourArea(b);
// Change sign depending on whether your want sorted small to big
// or big to small
if (areaA < areaB) {
return -1;
} else if (areaA > areaB) {
return 1;
}
return 0;
}
});
}