Ask Your Question
3

OpenCV4Android conversion from MatOfKeyPoint to MatOfPoint2f

asked 2013-01-17 13:26:02 -0600

mnut gravatar image

updated 2013-01-18 07:28:15 -0600

Andrey Pavlenko gravatar image

I am trying to use OpenCV for Android (OpenCV 2.4.3) I am writing a program to track keypoints. I am trying to use FeatureDetector to detect keypoints and then Video.calcOpticalFlowPyrLK to track them. The question that has me stumped is that the FeatureDetector function returns a MatOfKeyPoint while calcOpticalFlowPyrLK takes a MatOfPoint2f.

Here is my code so far:

//Feature detector for LKT flow estimation
FeatureDetector cvFeatureDetector;

//Vector of keypoints
MatOfKeyPoint keypoints;
...
//intitialize detector
cvFeatureDetector = FeatureDetector.create(FeatureDetector.GFTT);

keypoints = new MatOfKeyPoint();
...
//mPrevImgMat is a grayscale image - previous frame
//mCurrentImgMat is a grayscale image - current frame

//Run feature detector in previous image
cvFeatureDetector.detect(mPrevImgMat, keypoints);

MatOfPoint2f keypointsFound = new MatOfPoint2f();
MatOfByte keypointsStatus = new MatOfByte();
MatOfFloat err = new MatOfFloat();
Size winSize = new Size(25,25);
int maxLevel = 3;

//Optical flow to find keypoints in current image
Video.calcOpticalFlowPyrLK(mPrevImgMat, mCurrentImgMat, keypoints,
            keypointsFound, keypointsStatus, err, winSize, maxLevel);

//Obviously "keypoints" in the line above does not work. How does one covert
//keypoints to MatOfPoint2f?

Things I have tried unsuccessfully so far:

  1. keypoints.convertTo()
  2. Creating a vector from keypoints and then trying to populate a vector of Point Vector pointList. Then typecast to MatOfPoint2f when calling flow funciton (MatOfPoint2f) pointList
  3. Trying to populate a MatOfPoint2f from scratch. Cant figure out how to do this 4 Using fromArray method in MatOfPoint2f - Not sure what this method does. Documentation is blank for this method. Am I missing something obvious?
edit retag flag offensive close merge delete

4 answers

Sort by ยป oldest newest most voted
5

answered 2013-01-18 07:21:43 -0600

Andrey Pavlenko gravatar image

We have in plans the creation of docs for Java-specific OpenCV classes. For now let me share a short description of MatOfXxx Java classes here:

MatOfXxx classes (e.g. MatOfPoint) were introduced to avoid redundant copying of intermediate data between Java and native memory. E.g. you can get some large set of Points as the result of one OpenCV function and then pass it to another one. In C++ we use std::vector<cv::Point> for this. But use of ArrayList<org.opencv.core.Point> in Java caused copying all the Points data from native OpenCV level to Java when returning these Points and copying them back when calling the next OpenCV function using them. So for the sake of efficiency we switched to use of MatOfPoint class in such cases that is a kind of Mat of 1n or n1 dimensions that keeps a Point in each element (i.e. of type CV_32SC2 or CV_64FC2). As you may know, Mat keeps all the data on native level, so such objects can be passed between OpenCV calls without data copying. But if in your Java code at some point you need direct access to actual Points data there are toArray() and fromArray methods to explicit transfer data to/from Java.

So turning back to your particular question, to create a MatOfPoint2f containing the points corresponding to ones from existing MatOfKeyPoint you need:

  1. load KeyPoints to Java via MatOfKeyPoint.toArray()
  2. iterate through KeyPoint[] and create a corresponding Point[] (all of cv::Point, cv::Point2f and cv::Point2d are represented as org.opencv.core.Point in Java)
  3. use MatOfPoint2f.fromArray() or c-tor MatOfPoint2f(Point...pa)to put your Points to native level
edit flag offensive delete link more

Comments

Thank you very much! This helped immensely. I am new to OpenCV4Android. Is there a description about how data is transferred between java and native memory on OpenCV's website? Knowing that MatOfxxx are native objects would have been very useful for my understanding. @Andrey

mnut gravatar imagemnut ( 2013-01-26 23:22:53 -0600 )edit

This looks reasonable but only on one side, I don't know how often you need to get result from one method and pass this as is to another. In my opinion' it's quite often that you need to get result from one and pass it somehow modified/analized to another and in this case this api isn't convenient, it seems from implementation MapOfPoints is actually a Mat with single point, but with total*2 channels, this looks like a hack, but ok if it would help for performance, but there isn't any convenient methods getPoint, addPoint, removePoint, slicePoints etc, so either I don't see or I have always to get all points from native objects to java level, modify this as an array or a list, and put back to brand new MatOfPoint, this may cause very big overhead comparing to vector or List.

surcz gravatar imagesurcz ( 2020-09-28 09:48:36 -0600 )edit
1

answered 2013-01-18 00:11:34 -0600

Features2d.KeyPoint object include field pt that is point position. You need create MatOfKeyPoint with the same size as MatOfPoint2f and set pt field to each element from MatOfPoint2f that you have got from FeatureDetector algorithm.

edit flag offensive delete link more

Comments

This should work too, right?

Imgproc.findContours(mDilatedMat, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);

MatOfPoint2f points = new MatOfPoint2f();

for(int i=0; i < contours.size(); i++) {

contours.get(i).convertTo(points, CvType.CV_32FC2);

}

Al B gravatar imageAl B ( 2014-01-30 22:25:56 -0600 )edit

I dont think so, your going from List to just a MatOfPoint2f.

AbbeFaria gravatar imageAbbeFaria ( 2014-07-16 09:56:17 -0600 )edit
0

answered 2017-02-04 16:00:06 -0600

Here is a complete class that implements the conversion above:


import org.opencv.core.MatOfPoint; import org.opencv.core.Point;

import java.util.ArrayList;

import org.opencv.core.KeyPoint; import org.opencv.core.MatOfKeyPoint;

public class MatOfKeyPoint2MatOfPoint { public static MatOfPoint toMatOfPoint(MatOfKeyPoint mokp) { KeyPoint[] keyPoints = mokp.toArray(); ArrayList<point> arrayOfPoints = new ArrayList<point>();

    for(int i = 0; i < keyPoints.length; i++) {
        arrayOfPoints.add(keyPoints[i].pt);         
    }   

    MatOfPoint matOfPoint = new MatOfPoint();
    matOfPoint.fromList(arrayOfPoints);

    return matOfPoint;
}

}

edit flag offensive delete link more
0

answered 2016-06-02 01:12:39 -0600

Ahmed Arafa gravatar image

updated 2016-06-02 12:41:08 -0600

I had the exact same question. Thanks Andrey for your reply. Following up on your approach, the following worked flawlessly:

        1.  Call the feature detection algorithm (in this case I am extracting ORB features)

        mFeatureDetector.detect(matOpFlowPrev,
                 mMOKORbPrevKeypoints);

          2. Define: referenceKeypointsList = new ArrayList <KeyPoint>();

//    and loop about referenceKeypointsList  as follows:

         referenceKeypointsList = mMOKORbPrevKeypoints.toList();

         ListPointValues.clear();


    for(int i=0;i<referenceKeypointsList.size();i++){

             dxx= referenceKeypointsList.get(i).pt.x;
            dyy= referenceKeypointsList.get(i).pt.y;

    //   Define new point and add corresponding values to ListPointValues:

             Point ppV = new Point(dxx,dyy);

            ListPointValues.add(i, ppV);

// note ListPointValues is defined as: private List<point> ListPointValues

         }

        3.  mMOP2fptsPrev.fromList(ListPointValues);
edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2013-01-17 13:26:02 -0600

Seen: 8,190 times

Last updated: Jun 02 '16