Best way to convert an opencv matrix to string for storage in database in Android (Java)

4.1k views Asked by At

I want to store a descriptor matrix generated by a random OpenCV descriptor extractor as a database entity.

Assuming desc is the descriptor Matrix

String s = (desc.reshape(1,1)).dump;

To get the matrix back from the database, I did

Mat desc = new Mat(numberOfRows * numberOfCols * numberOfChannels, 1, type);
/* I stored number of rows and number of cols and type of the matrix separately and pass them to the function that returns the matrix */
String ss[] = s.substring(1, s.length -1).split(", ");
int[] temp = new int[sss.length ];
for(int i = 0; i < sss.length; i++) temp [i] = Integer.parseInt(sss[i]);
MatOfInt int_values = new MatOfInt(temp);
int_values.convertTo(desc, type);
desc = fingerprint.desc(numberOfChannels, numberOfRows);

This works fine but takes a lot of time, especially the .split method and the loop involving parseInt due to the large number of elements in the matrix (about 100k in my case).

My question is: is there a better way to do this?

my second question is, come on, assigning a 100K long string array and parsing it (given the fact that the strings are actually 2-3 characters at most) shouldn't really take 2 seconds, is it because Android/Java is slow

2

There are 2 answers

2
kiranpradeep On BEST ANSWER

OpenCV provides FileStorage class for persistence as in link. Basically the Mat image could be saved as XML/YAML file from which we could read later. A simple example will be as below.

//for writing
cv::FileStorage store(“save.yml", cv::FileStorage::WRITE);
store << “mat” << img;
store.release();

//for reading
cv::FileStorage store(“save.yml", cv::FileStorage::READ);
store[“mat”] >> img;
store.release();

But we don't have FileStorage java wrapper in Android. Alternative could be invoking above code over JNI as in this example or even better - check Berak's sample.

0
stopBugs On

Ok, I found a solution a bit similar to Berak as Kiran mentioned. My attempt is a bit less general but works fine for descriptor matrices, is fast and does not involve jni.

        // for writing
        MatOfByte bytes = new MatOfByte(desc.reshape(1, nrows * ncols * nchannels));
        byte[] bytes_ = bytes.toArray();

        String s = Base64.encodeToString(bytes_, Base64.DEFAULT);


        // for reading
        byte[] bytes_ = Base64.decode(s, Base64.DEFAULT);
        MatOfByte bytes = new MatOfByte(bytes_);
        Mat desc  = new Mat(nrows * ncols * nchannels, 1, type);
        bytes.convertTo(desc, type);

        desc = desc.reshape(nchannels, nrows);