Although I have not run timings, I suspect that going through formats such as XML or JSON would require more space and computing resources than using primitives.
Below is some code that can be used to save and retrieve MatOfKeyPoint to SQLite database in an Android environment. This is using OpenCV 2.4.11 so SIFT is available.
What you see when you run this application is your test image (which you need to supply and put in the drawable folder) with added keypoints.
The siftTest()
method starts by computing keyPoints
which is MatOfKeyPoint
type. The code saves the underlying data of that object in the database, then reads that data out and creates a new object keyPointsFromDb
, the contents of which are applied to the original image and the result is displayed.
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("native-lib");
System.loadLibrary("opencv_java");
System.loadLibrary("nonfree");
}
private ImageView imageView;
private Bitmap inputImage; // make bitmap from image resource
private FeatureDetector detector = FeatureDetector.create(FeatureDetector.SIFT);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
inputImage = BitmapFactory.decodeResource(getResources(), R.drawable.test);
imageView = (ImageView) this.findViewById(R.id.imageView);
siftTest();
}
public void siftTest() {
Mat rgba = new Mat();
Utils.bitmapToMat(inputImage, rgba);
MatOfKeyPoint keyPoints = new MatOfKeyPoint();
Imgproc.cvtColor(rgba, rgba, Imgproc.COLOR_RGBA2GRAY);
detector.detect(rgba, keyPoints);
// Save to database
MatchingDatabaseAdapter.addKeypoints(keyPoints, getApplicationContext());
// Opens database cursor
MatchingDatabaseAdapter.getAllRecordsCursor(getApplicationContext());
// Gets the first item in the database (as an example... you could loop through many/all)
MatOfKeyPoint keyPointsFromDb = MatchingDatabaseAdapter.getKeypointsFromNextCursorPosition();
// Closes database
MatchingDatabaseAdapter.closeDb();
Features2d.drawKeypoints(rgba, keyPointsFromDb, rgba);
Utils.matToBitmap(rgba, inputImage);
imageView.setImageBitmap(inputImage);
}
}
Here is the database code which contains some details associated with converting to the byte array required for the database. I didn't include everything associated with using a database, since that's really a different topic.
public class MatchingDatabaseAdapter {
...
...
...
public static void addKeypoints(MatOfKeyPoint keyPoints, Context context) {
float[] data = new float[(int)keyPoints.total() * keyPoints.channels()]; // make a spot to save the data
keyPoints.get(0,0,data); // load the data;
ByteBuffer buffer = ByteBuffer.allocate(data.length * 4);
for (int i = 0; i < data.length; i++){
buffer.putFloat(data[i]);
}
byte[] byteArray = buffer.array();
addBlob(byteArray, keyPoints.rows(), keyPoints.cols(), keyPoints.type(), context);
}
public static void addBlob(byte[] blob, int rows, int columns, int mattype, Context context) throws SQLException {
if (mDb == null) mDb = openDb(context);
ContentValues contentValues = new ContentValues();
contentValues.put(DatabaseHelper.BLOB_FIELD_NAME, blob);
contentValues.put(DatabaseHelper.ROWS_FIELD_NAME, rows);
contentValues.put(DatabaseHelper.COLUMNS_FIELD_NAME, columns);
contentValues.put(DatabaseHelper.MATTYPE_FIELD_NAME, mattype);
long x = mDb.insert(DatabaseHelper.TABLE_NAME, null, contentValues);
Log.v(TAG, "insert said " + x + " and blob was " + blob.length + " long.");
closeDb();
}
public static Cursor getAllRecordsCursor(Context context) {
if (mDb == null || !mDb.isOpen()) mDb = openDb(context);
mCursor = mDb.query(DatabaseHelper.TABLE_NAME, null, null, null, null,null, null);
boolean hasRecords = mCursor.moveToFirst();
Log.v(TAG, "MatchingDatabaseAdapter.getAllRecordsCursor() cursor created. " + mCursor + " and " + (hasRecords?"has records":"has NO RECORDS"));
return mCursor;
}
public static MatOfKeyPoint getKeypointsFromNextCursorPosition() {
MatOfKeyPoint keyPoints = null;
if (mCursor != null) {
Log.v(TAG, "mCursor has ...
(more)
I'm not sure about android, but OpenCV provides a FileStorage class that allows you to write matrices to text files as XML or YAML. That is usually sufficient. If your Mat can reasonably be represented as an image, you can just save them to pngs as well
Last time I checked FileStorage is not ported for android - like it says in the stackoverflow linked in the question.