I'm trying to calculate the degree of similarity between two images but it gives me 0 every time.
This is my code:
public class TemplateMatching{
static void analyze(Mat image, MatOfKeyPoint keypoints, Mat descriptors){
detector.detect(image, keypoints);
extractor.compute(image, keypoints, descriptors);
}
static FeatureDetector detector= FeatureDetector.create(FeatureDetector.ORB);
static DescriptorExtractor extractor = DescriptorExtractor.create(DescriptorExtractor.BRIEF);
final static DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);
static void ana(Mat image, MatOfKeyPoint keypoints, Mat descriptors){
detector.detect(image, keypoints);
extractor.compute(image, keypoints, descriptors);
}
static MatOfDMatch filterMatchesByDistance(MatOfDMatch matches){
List<DMatch> matches_original = matches.toList();
List<DMatch> matches_filtered = new ArrayList<DMatch>();
int DIST_LIMIT = 30;
// Check all the matches distance and if it passes add to list of filtered matches
Log.d("DISTFILTER", "ORG SIZE:" + matches_original.size() + "");
for (int i = 0; i < matches_original.size(); i++) {
DMatch d = matches_original.get(i);
if (Math.abs(d.distance) <= DIST_LIMIT) {
matches_filtered.add(d);
}
}
Log.d("DISTFILTER", "FIL SIZE:" + matches_filtered.size() + "");
MatOfDMatch mat = new MatOfDMatch();
mat.fromList(matches_filtered);
return mat;
}
public int comparer(Mat frame,Mat test) {
// Info to store analysis stats
int distance=0;
MatOfKeyPoint keypoints_o = new MatOfKeyPoint();
MatOfKeyPoint keypoints_t = new MatOfKeyPoint();
Mat descriptors_o = new Mat();
Mat descriptors_t = new Mat();
// Detect key points and compute descriptors for inputFrame
ana(frame, keypoints_o, descriptors_o);
ana(test, keypoints_t, descriptors_t);
// Compute matches
MatOfDMatch matches = new MatOfDMatch();
matcher.match(descriptors_o, descriptors_t, matches);
// Filter matches by distance
MatOfDMatch filtered = filterMatchesByDistance(matches);
// If count of matches is OK, apply homography check
distance = (int) filtered.size().height;
return (distance);
}
The distance is 0 every time. If I give the same image, it also gives me 0 for distance.
Related
I am new to OpenCV and I am trying to write an android code using OpenCV to compare two images for similarities, for my example i loaded two images from Drawable folder as you see in the code, but i am not able to complete the code in order to get a percentage of matching between images and to set a threshold or something? so please can any one help me solving my issue, thank you in advance. below is my Code:
public class MainActivity extends AppCompatActivity {
//TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
System.loadLibrary("opencv_java3");
// textView =(TextView)findViewById(R.id.textView);
Mat m1 = Imgcodecs.imread(ResourcesCompat.getDrawable(getResources(), R.drawable.image1, null).toString());
Mat m2 = Imgcodecs.imread(ResourcesCompat.getDrawable(getResources(), R.drawable.image2, null).toString());
//Imgproc.cvtColor(m1, m1, Imgproc.COLOR_RGB2BGRA);
//Imgproc.cvtColor(m2, m2, Imgproc.COLOR_RGB2BGRA);
FeatureDetector detector = FeatureDetector.create(FeatureDetector.ORB);
MatOfKeyPoint keypoints1 = new MatOfKeyPoint();
detector.detect(m1, keypoints1);
FeatureDetector detector2 = FeatureDetector.create(FeatureDetector.ORB);
MatOfKeyPoint keypoints2 = new MatOfKeyPoint();
detector2.detect(m2, keypoints2);
DescriptorExtractor extractor = DescriptorExtractor.create(DescriptorExtractor.ORB);
Mat descriptors1 = new Mat();
extractor.compute(m1, keypoints1, descriptors1);
DescriptorExtractor extractor2 = DescriptorExtractor.create(DescriptorExtractor.ORB);
Mat descriptors2 = new Mat();
extractor2.compute(m2, keypoints2, descriptors2);
DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);
MatOfDMatch matches = new MatOfDMatch();
matcher.match(descriptors1, descriptors2, matches);
List<DMatch> matchesList = matches.toList();
double maxDistance = 0;
double minDistance = 1000;
int rowCount = matchesList.size();
for (int i = 0; i < rowCount; i++)
{
double dist = matchesList.get(i).distance;
if (dist < minDistance) minDistance = dist;
if (dist > maxDistance) maxDistance = dist;
}
List<DMatch> goodMatchesList = new ArrayList<DMatch>();
double upperBound = 1.6 * minDistance;
for (int i = 0; i < rowCount; i++)
{
if (matchesList.get(i).distance <= upperBound)
{
goodMatchesList.add(matchesList.get(i));
}
}
MatOfDMatch goodMatches = new MatOfDMatch();
goodMatches.fromList(goodMatchesList);
}
}
I am very new to android and openCV, I'M working on "Android application: plant disease Analyzer".
Below is my workflow:
1.I have static plant diseases in my gallery
2.End-user can capture an plant disease and submit to my application.
3.I want to compare the processed image with my gallery(Diseases) to get the most similar disease
Can any one tell me What will be the best algorithm to use?,
I have been searching on google but no luck,I tried with
below code snippet, which I tried using openCV :
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
Bitmap camerabitmap = BitmapFactory.decodeFile(cameraimage,
bmOptions);
Bitmap galareybitmap =
BitmapFactory.decodeFile(galImage.getAbsolutePath(), bmOptions);
private double imageProcessing(Bitmap cameraimage,Bitmap
galimagebitmap,String galimagename) throws IOException {
Mat img1 = new Mat();
Utils.bitmapToMat(cameraimage, img1);
Mat img2 = new Mat();
Utils.bitmapToMat(gallimagebitmap, img2);
Imgproc.cvtColor(img1, img1, Imgproc.COLOR_RGBA2GRAY);
Imgproc.cvtColor(img2, img2, Imgproc.COLOR_RGBA2GRAY);
img1.convertTo(img1, CvType.CV_32F);
img2.convertTo(img2, CvType.CV_32F);
//Log.d("ImageComparator", "img1:"+img1.rows()+"x"+img1.cols()+" img2:"+img2.rows()+"x"+img2.cols());
Mat hist1 = new Mat();
Mat hist2 = new Mat();
MatOfInt histSize = new MatOfInt(180);
MatOfInt channels = new MatOfInt(0);
ArrayList<Mat> bgr_planes1= new ArrayList<Mat>();
ArrayList<Mat> bgr_planes2= new ArrayList<Mat>();
Core.split(img1, bgr_planes1);
Core.split(img2, bgr_planes2);
MatOfFloat histRanges = new MatOfFloat(0f, 256f);
boolean accumulate = false;
Imgproc.calcHist(bgr_planes1, channels, new Mat(), hist1, histSize, histRanges);
Core.normalize(hist1, hist1, 0, hist1.rows(), Core.NORM_MINMAX, -1, new Mat());
Imgproc.calcHist(bgr_planes2, channels, new Mat(), hist2, histSize, histRanges);
Core.normalize(hist2, hist2, 0, hist2.rows(), Core.NORM_MINMAX, -1, new Mat());
/ img1.convertTo(img1, CvType.CV_32F);
// img2.convertTo(img2, CvType.CV_32F);
hist1.convertTo(hist1, CvType.CV_32F);
hist2.convertTo(hist2, CvType.CV_32F);
return Imgproc.compareHist(hist1, hist2,3);
}
I tried with template matching also in opencv
int match_method=Imgproc.TM_CCOEFF_NORMED;
Mat temp = Imgcodecs.imread(tempim,Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE );
Mat img = Imgcodecs.imread(sourceim,Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE
);
Size sz = new Size(200, 200);
Mat resizeimage = new Mat();
Imgproc.resize(img, resizeimage, sz);
Mat sourceimage = resizeimage;
Mat resizeimage2 = new Mat();
Imgproc.resize(temp, resizeimage2, sz);
Mat templateimage = resizeimage2;
int result_cols = sourceimage.cols() - templateimage.cols() + 1;
int result_rows = sourceimage.rows() - templateimage.rows() + 1;
Mat result = new Mat(result_rows, result_cols, CvType.CV_32FC1);
Imgproc.matchTemplate(sourceimage,templateimage, result, match_method);
//Core.normalize(result, result, 0, 1, Core.NORM_MINMAX, -1, new Mat());
Imgproc.threshold(result, result,0.1,1,Imgproc.THRESH_TOZERO);
Point matchLoc,maxLoc,minLoc;
Core.MinMaxLocResult mmr;
boolean iterate = true;
double minlocvalue,maxlocvalue,minminvalue,maxmaxvalue;
while(true){
mmr = Core.minMaxLoc(result);
if (match_method == Imgproc.TM_SQDIFF || match_method == Imgproc.TM_SQDIFF_NORMED) {
matchLoc = mmr.minLoc;
minminvalue = mmr.minVal; // test
} else {
matchLoc = mmr.maxLoc;
maxmaxvalue = mmr.minVal; // test
}
Log.d(TAG, "mmr.maxVal : "+mmr.maxVal);
if(mmr.maxVal >=0.2)
{
Log.d(TAG, "imagemathed..");
Imgproc.rectangle(sourceimage, matchLoc, new Point(matchLoc.x + templateimage.cols(),
matchLoc.y + templateimage.rows()), new Scalar(0, 255, 0));
Imgcodecs.imwrite(outFile, img);
Mat image = Imgcodecs.imread(outFile);
try {
Bitmap bm = Bitmap.createBitmap(image.cols(), image.rows(), Bitmap.Config.RGB_565);
Utils.matToBitmap(image, bm);
System.out.println("MinVal "+bm);
}catch(Exception e){
e.printStackTrace();
}
return true;
}else {
Log.d(TAG, "image not mathced..");
return false;
}
}
But every time I'M not getting the proper output, fault images are coming in the output.Please help me out, AM I following right approach, If not can some one suggest me which approach i have to follow.
I'm using opencv4android 3.2, to find a known object I'm using findHomography method and, when I capture an image where the object farther away from the camera it gives me a good result, but when I capture an image where the object closer away from the camera I got a bad result.
object to find
result
this is my code
// Matches current frame's descriptors to template's
descriptorMatcher.match(descriptors, templateDescriptors,
matches);
List<DMatch> matchesList = matches.toList();
double maxDistance = 0;
double minDistance = 100;
int rowCount = descriptors.rows();
for (int i = 0; i < rowCount; i++) {
double dist = matchesList.get(i).distance;
if (dist < minDistance) minDistance = dist;
if (dist > maxDistance) maxDistance = dist;
}
List<DMatch> goodMatchesList = new ArrayList<>();
double upperBound = 3 * minDistance;
for (int i = 0; i < rowCount; i++) {
if (matchesList.get(i).distance <= upperBound) {
goodMatchesList.add(matchesList.get(i));
}
}
// Iterate through good matches and put the 2D points of the
object (template) and frame (scene) into a list
List<KeyPoint> objKpList = new ArrayList<>();
List<KeyPoint> sceneKpList = new ArrayList<>();
objKpList = templateKeypoints.toList();
sceneKpList = keypoints.toList();
LinkedList<Point> objList = new LinkedList<>();
LinkedList<Point> sceneList = new LinkedList<>();
for (int i = 0; i < goodMatchesList.size(); i++) {
objList.addLast(objKpList.get(goodMatchesList.get(i).trainIdx).pt);
sceneList.addLast(sceneKpList.get(goodMatchesList.get(i).queryIdx).pt);
}
MatOfPoint2f obj = new MatOfPoint2f();
MatOfPoint2f scene = new MatOfPoint2f();
obj.fromList(objList);
scene.fromList(sceneList);
// Calculate the homography
Mat H = Calib3d.findHomography(obj, scene, Calib3d.RANSAC, 3);
...
try {
Core.perspectiveTransform(objCorners, sceneCorners, H);
Point p1 = new Point(sceneCorners.get(0, 0));
Point p2 = new Point(sceneCorners.get(1, 0));
Point p3 = new Point(sceneCorners.get(2, 0));
Point p4 = new Point(sceneCorners.get(3, 0));
final List<Point> source = new ArrayList<Point>();
source.add(p1);
source.add(p2);
source.add(p3);
source.add(p4);
Mat startM = Converters.vector_Point2f_to_Mat(source);
flip(startM, startM, -1);
Mat result = warp(rgba, startM);
Bitmap bmppp = Bitmap.createBitmap(result.width(),
result.height(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(result, bmppp);
keypoints.release();
SaveImage(result);
} catch (CvException e) {
e.printStackTrace();
Log.e(TAG, "perspectiveTransform returned an assertion
failed error.");
return false;
}
why i don't got the good result findHomography?
Thanks.
this is the template using to find the card object
I was having the same problem. It sounds silly, but have you tried to switch the srcPoints with destinationPoints?
I'm using homography to control the navigation of a robot. I originally had:
M, mask = cv2.findHomography(robotPoints, visionpoints)
However, by switching the robotPoints with the visionPoints it worked. I was reverse mapping the planes.
M, mask = cv2.findHomography(visionPoints,robotPoints)
I'm OpenCV learner. I was trying Image Comparison. I have used OpenCV 2.4.13.3
I have these two images 1.jpg and cam1.jpg.
When I use the following command in openCV
File sdCard = Environment.getExternalStorageDirectory();
String path1, path2;
path1 = sdCard.getAbsolutePath() + "/1.jpg";
path2 = sdCard.getAbsolutePath() + "/cam1.jpg";
FeatureDetector detector = FeatureDetector.create(FeatureDetector.ORB);
DescriptorExtractor extractor = DescriptorExtractor.create(DescriptorExtractor.BRIEF);
DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);
Mat img1 = Highgui.imread(path1);
Mat img2 = Highgui.imread(path2);
Mat descriptors1 = new Mat();
MatOfKeyPoint keypoints1 = new MatOfKeyPoint();
detector.detect(img1, keypoints1);
extractor.compute(img1, keypoints1, descriptors1);
//second image
// Mat img2 = Imgcodecs.imread(path2);
Mat descriptors2 = new Mat();
MatOfKeyPoint keypoints2 = new MatOfKeyPoint();
detector.detect(img2, keypoints2);
extractor.compute(img2, keypoints2, descriptors2);
//matcher image descriptors
MatOfDMatch matches = new MatOfDMatch();
matcher.match(descriptors1,descriptors2,matches);
// Filter matches by distance
MatOfDMatch filtered = filterMatchesByDistance(matches);
int total = (int) matches.size().height;
int Match= (int) filtered.size().height;
Log.d("LOG", "total:" + total + " Match:"+Match);
Method filterMatchesByDistance
static MatOfDMatch filterMatchesByDistance(MatOfDMatch matches){
List<DMatch> matches_original = matches.toList();
List<DMatch> matches_filtered = new ArrayList<DMatch>();
int DIST_LIMIT = 30;
// Check all the matches distance and if it passes add to list of filtered matches
Log.d("DISTFILTER", "ORG SIZE:" + matches_original.size() + "");
for (int i = 0; i < matches_original.size(); i++) {
DMatch d = matches_original.get(i);
if (Math.abs(d.distance) <= DIST_LIMIT) {
matches_filtered.add(d);
}
}
Log.d("DISTFILTER", "FIL SIZE:" + matches_filtered.size() + "");
MatOfDMatch mat = new MatOfDMatch();
mat.fromList(matches_filtered);
return mat;
}
Log
total:122 Match:30
As we can see from the log match is 30.
But as we can see both images have same visual element (in).
How can I get match=90 using openCV?
It would be great if somebody can help with code snippet.
If using opencv it is not possible then what are the other
alternatives we can look for?
But as we can see both images have same visual element (in).
So, we should compare not whole images, but "same visual element" on it. You can improve Match value more if you do not compare the "template" and "camera" images themselves, but processed same way (converted to binary black/white, for example) "template" and "camera" images. For example, try to find blue (background of template logo) square on both ("template" and "camera") images and compare that squares (Region Of Interest). The code may be something like that:
Bitmap bmImageTemplate = <get your template image Bitmap>;
Bitmap bmTemplate = findLogo(bmImageTemplate); // process template image
Bitmap bmImage = <get your camera image Bitmap>;
Bitmap bmLogo = findLogo(bmImage); // process camera image same way
compareBitmaps(bmTemplate, bmLogo);
where
private Bitmap findLogo(Bitmap sourceBitmap) {
Bitmap roiBitmap = null;
Mat sourceMat = new Mat(sourceBitmap.getWidth(), sourceBitmap.getHeight(), CvType.CV_8UC3);
Utils.bitmapToMat(sourceBitmap, sourceMat);
Mat roiTmp = sourceMat.clone();
final Mat hsvMat = new Mat();
sourceMat.copyTo(hsvMat);
// convert mat to HSV format for Core.inRange()
Imgproc.cvtColor(hsvMat, hsvMat, Imgproc.COLOR_RGB2HSV);
Scalar lowerb = new Scalar(85, 50, 40); // lower color border for BLUE
Scalar upperb = new Scalar(135, 255, 255); // upper color border for BLUE
Core.inRange(hsvMat, lowerb, upperb, roiTmp); // select only blue pixels
// find contours
List<MatOfPoint> contours = new ArrayList<>();
List<Rect> squares = new ArrayList<>();
Imgproc.findContours(roiTmp, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
// find appropriate bounding rectangles
for (MatOfPoint contour : contours) {
MatOfPoint2f areaPoints = new MatOfPoint2f(contour.toArray());
RotatedRect boundingRect = Imgproc.minAreaRect(areaPoints);
double rectangleArea = boundingRect.size.area();
// test min ROI area in pixels
if (rectangleArea > 400) {
Point rotated_rect_points[] = new Point[4];
boundingRect.points(rotated_rect_points);
Rect rect = Imgproc.boundingRect(new MatOfPoint(rotated_rect_points));
double aspectRatio = rect.width > rect.height ?
(double) rect.height / (double) rect.width : (double) rect.width / (double) rect.height;
if (aspectRatio >= 0.9) {
squares.add(rect);
}
}
}
Mat logoMat = extractSquareMat(roiTmp, getBiggestSquare(squares));
roiBitmap = Bitmap.createBitmap(logoMat.cols(), logoMat.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(logoMat, roiBitmap);
return roiBitmap;
}
method extractSquareMat() just extract Region of Interest (logo) from whole image
public static Mat extractSquareMat(Mat sourceMat, Rect rect) {
Mat squareMat = null;
int padding = 50;
if (rect != null) {
Rect truncatedRect = new Rect((int) rect.tl().x + padding, (int) rect.tl().y + padding,
rect.width - 2 * padding, rect.height - 2 * padding);
squareMat = new Mat(sourceMat, truncatedRect);
}
return squareMat ;
}
and compareBitmaps() just wrapper for your code:
private void compareBitmaps(Bitmap bitmap1, Bitmap bitmap2) {
Mat mat1 = new Mat(bitmap1.getWidth(), bitmap1.getHeight(), CvType.CV_8UC3);
Utils.bitmapToMat(bitmap1, mat1);
Mat mat2 = new Mat(bitmap2.getWidth(), bitmap2.getHeight(), CvType.CV_8UC3);
Utils.bitmapToMat(bitmap2, mat2);
compareMats(mat1, mat2);
}
your code as method:
private void compareMats(Mat img1, Mat img2) {
FeatureDetector detector = FeatureDetector.create(FeatureDetector.ORB);
DescriptorExtractor extractor = DescriptorExtractor.create(DescriptorExtractor.BRIEF);
DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);
Mat descriptors1 = new Mat();
MatOfKeyPoint keypoints1 = new MatOfKeyPoint();
detector.detect(img1, keypoints1);
extractor.compute(img1, keypoints1, descriptors1);
//second image
// Mat img2 = Imgcodecs.imread(path2);
Mat descriptors2 = new Mat();
MatOfKeyPoint keypoints2 = new MatOfKeyPoint();
detector.detect(img2, keypoints2);
extractor.compute(img2, keypoints2, descriptors2);
//matcher image descriptors
MatOfDMatch matches = new MatOfDMatch();
matcher.match(descriptors1,descriptors2,matches);
// Filter matches by distance
MatOfDMatch filtered = filterMatchesByDistance(matches);
int total = (int) matches.size().height;
int Match= (int) filtered.size().height;
Log.d("LOG", "total:" + total + " Match:" + Match);
}
static MatOfDMatch filterMatchesByDistance(MatOfDMatch matches){
List<DMatch> matches_original = matches.toList();
List<DMatch> matches_filtered = new ArrayList<DMatch>();
int DIST_LIMIT = 30;
// Check all the matches distance and if it passes add to list of filtered matches
Log.d("DISTFILTER", "ORG SIZE:" + matches_original.size() + "");
for (int i = 0; i < matches_original.size(); i++) {
DMatch d = matches_original.get(i);
if (Math.abs(d.distance) <= DIST_LIMIT) {
matches_filtered.add(d);
}
}
Log.d("DISTFILTER", "FIL SIZE:" + matches_filtered.size() + "");
MatOfDMatch mat = new MatOfDMatch();
mat.fromList(matches_filtered);
return mat;
}
As result for resized (scaled for 50%) images saved from your question result is:
D/DISTFILTER: ORG SIZE:237
D/DISTFILTER: FIL SIZE:230
D/LOG: total:237 Match:230
NB! This is a quick and dirty example just to demonstrate approach only for given template.
P.S. getBiggestSquare() can be like that (based on compare by area):
public static Rect getBiggestSquare(List<Rect> squares) {
Rect biggestSquare = null;
if (squares != null && squares.size() >= 1) {
Rect square;
double maxArea;
int ixMaxArea = 0;
square = squares.get(ixMaxArea);
maxArea = square.area();
for (int ix = 1; ix < squares.size(); ix++) {
square = squares.get(ix);
if (square.area() > maxArea) {
maxArea = square.area();
ixMaxArea = ix;
}
}
biggestSquare = squares.get(ixMaxArea);
}
return biggestSquare;
}
I am trying to implement Paper detection through OpenCV. I am able to understand the concept of how can I get it,
Input-> Canny-> Blur-> Find Conture-> Search (closed)Quadrilateral-> Draw Conture
but still, I am new to OpenCV programming. So having issues in implementing it. I was able to find help through this answer
Android OpenCV Paper Sheet detection
but it's drawing contour on every possible lining. Here is the code I am trying to implement.
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
mRgba = inputFrame.rgba();
Imgproc.drawContours(mRgba,findContours(mRgba), 0, new Scalar(0 , 255, 0), 5);
return mRgba;
}
public static class Quadrilateral {
public MatOfPoint contour;
public Point[] points;
public Quadrilateral(MatOfPoint contour, Point[] points) {
this.contour = contour;
this.points = points;
}
}
public static Quadrilateral findDocument( Mat inputRgba ) {
ArrayList<MatOfPoint> contours = findContours(inputRgba);
Quadrilateral quad = getQuadrilateral(contours);
return quad;
}
private static ArrayList<MatOfPoint> findContours(Mat src) {
double ratio = src.size().height / 500;
int height = Double.valueOf(src.size().height / ratio).intValue();
int width = Double.valueOf(src.size().width / ratio).intValue();
Size size = new Size(width,height);
Mat resizedImage = new Mat(size, CvType.CV_8UC4);
Mat grayImage = new Mat(size, CvType.CV_8UC4);
Mat cannedImage = new Mat(size, CvType.CV_8UC1);
Imgproc.resize(src,resizedImage,size);
Imgproc.cvtColor(resizedImage, grayImage, Imgproc.COLOR_RGBA2GRAY, 4);
Imgproc.GaussianBlur(grayImage, grayImage, new Size(5, 5), 0);
Imgproc.Canny(grayImage, cannedImage, 75, 200);
ArrayList<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Mat hierarchy = new Mat();
Imgproc.findContours(cannedImage, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
hierarchy.release();
Collections.sort(contours, new Comparator<MatOfPoint>() {
#Override
public int compare(MatOfPoint lhs, MatOfPoint rhs) {
return Double.valueOf(Imgproc.contourArea(rhs)).compareTo(Imgproc.contourArea(lhs));
}
});
resizedImage.release();
grayImage.release();
cannedImage.release();
return contours;
}
private static Quadrilateral getQuadrilateral(ArrayList<MatOfPoint> contours) {
for ( MatOfPoint c: contours ) {
MatOfPoint2f c2f = new MatOfPoint2f(c.toArray());
double peri = Imgproc.arcLength(c2f, true);
MatOfPoint2f approx = new MatOfPoint2f();
Imgproc.approxPolyDP(c2f, approx, 0.02 * peri, true);
Point[] points = approx.toArray();
// select biggest 4 angles polygon
if (points.length == 4) {
Point[] foundPoints = sortPoints(points);
return new Quadrilateral(c, foundPoints);
}
}
return null;
}
private static Point[] sortPoints(Point[] src) {
ArrayList<Point> srcPoints = new ArrayList<>(Arrays.asList(src));
Point[] result = { null , null , null , null };
Comparator<Point> sumComparator = new Comparator<Point>() {
#Override
public int compare(Point lhs, Point rhs) {
return Double.valueOf(lhs.y + lhs.x).compareTo(rhs.y + rhs.x);
}
};
Comparator<Point> diffComparator = new Comparator<Point>() {
#Override
public int compare(Point lhs, Point rhs) {
return Double.valueOf(lhs.y - lhs.x).compareTo(rhs.y - rhs.x);
}
};
// top-left corner = minimal sum
result[0] = Collections.min(srcPoints, sumComparator);
// bottom-right corner = maximal sum
result[2] = Collections.max(srcPoints, sumComparator);
// top-right corner = minimal diference
result[1] = Collections.min(srcPoints, diffComparator);
// bottom-left corner = maximal diference
result[3] = Collections.max(srcPoints, diffComparator);
return result;
}
The answer suggests that I should use Quadrilateral Object and call it with Imgproc.drawContours(), but this function takes in ArrayList as argument where as Quadrilateral object contains MatofPoint and Point[]. Can someone help me through this..I am using OpenCV(3.3) and Android (1.5.1)?
Here is the sample what it should look like