javaandroidopencvmatsift

Saving opencv Mat and MatOfKeyPoint [ ANDROID JAVA ]


I am using SIFT by opencv in android studio JAVA language. I want to save the features of the image which are Mat and MatOfKeyPoint so that next for the same image I don't have to recalculate those features.

So far I have tried :

  1. TinyDB

ISSUE : It gets the data corrupted when app is restarted. Below is the code I used to save for Mat, same I have applied for MatOfKeyPoint too

tinyDB.putObject("MAT_DATA", (Object) mat_descriptors);

for reading I am using this

Log.d("TINYDB_", "MAT : "+tinyDB.getObject("MAT_DATA", Mat.class)+"");

below are logs while I am reading object,

  1. When app is not restarted after putObject
2022-08-15 11:15:35.166 5143-5143/com.programminghut.opencv D/TINYDB_: MAT : Mat [ 59868*128*CV_32FC1, isCont=true, isSubmat=false, nativeObj=0xb4000071f399bcb0, dataAddr=0xb4000070f2d8e000 ]
  1. When app is restarted and putObject is not called
2022-08-15 11:16:09.405 5268-5268/com.programminghut.opencv D/TINYDB_: MAT : Mat [ -1*-1*CV_8UC1, isCont=true, isSubmat=false, nativeObj=0xb4000071f399bcb0, dataAddr=0x0 ]

Now I am looking either solution to the above tinyDB problem or If you think anything else could utilised to save Mat into local storage that would also be very helpful.


Solution

  • Thanks to @sorifiend I was able to store Mat via tinyDB.

    how-to-serialize-deserialize-opencv-mat-in-java :- It works for only for Mat

    I did more googling and found a solution on stack overflow for MatOfKeyPoint too but can not find link to it.

    So below is the class I made after combining both the solutions :

    
    import com.google.gson.Gson;
    import com.google.gson.JsonArray;
    import com.google.gson.JsonObject;
    import com.google.gson.JsonParser;
    
    import org.opencv.core.KeyPoint;
    import org.opencv.core.Mat;
    import org.opencv.core.MatOfKeyPoint;
    import org.opencv.core.Point;
    
    class SerializeTheMat
    {
        public static String keypointsToJson(MatOfKeyPoint mat){
            if(mat!=null && !mat.empty()){
                Gson gson = new Gson();
    
                JsonArray jsonArr = new JsonArray();
    
                KeyPoint[] array = mat.toArray();
                for(int i=0; i<array.length; i++){
                    KeyPoint kp = array[i];
    
                    JsonObject obj = new JsonObject();
    
                    obj.addProperty("class_id", kp.class_id);
                    obj.addProperty("x",        kp.pt.x);
                    obj.addProperty("y",        kp.pt.y);
                    obj.addProperty("size",     kp.size);
                    obj.addProperty("angle",    kp.angle);
                    obj.addProperty("octave",   kp.octave);
                    obj.addProperty("response", kp.response);
    
                    jsonArr.add(obj);
                }
    
                String json = gson.toJson(jsonArr);
    
                return json;
            }
            return "{}";
        }
    
        public static MatOfKeyPoint keypointsFromJson(String json){
            MatOfKeyPoint result = new MatOfKeyPoint();
    
            JsonParser parser = new JsonParser();
            JsonArray jsonArr = parser.parse(json).getAsJsonArray();
    
            int size = jsonArr.size();
    
            KeyPoint[] kpArray = new KeyPoint[size];
    
            for(int i=0; i<size; i++){
                KeyPoint kp = new KeyPoint();
    
                JsonObject obj = (JsonObject) jsonArr.get(i);
    
                Point point = new Point(
                        obj.get("x").getAsDouble(),
                        obj.get("y").getAsDouble()
                );
    
                kp.pt       = point;
                kp.class_id = obj.get("class_id").getAsInt();
                kp.size     =     obj.get("size").getAsFloat();
                kp.angle    =    obj.get("angle").getAsFloat();
                kp.octave   =   obj.get("octave").getAsInt();
                kp.response = obj.get("response").getAsFloat();
    
                kpArray[i] = kp;
            }
    
            result.fromArray(kpArray);
    
            return result;
        }
    
    
    
    
    
    
    
        //  Serialization/deserialization utility
        public static String SerializeFromMat(Mat mat)
        {
            SerializedMat serializedMat = new SerializedMat();
            serializedMat.setType(mat.type());
            serializedMat.setRows(mat.rows());
            serializedMat.setCols(mat.cols());
    
            if (serializedMat.getType()==0||
                    serializedMat.getType()==8||
                    serializedMat.getType()==16||
                    serializedMat.getType()==24)
            {
                serializedMat.setBytes(new byte[(int)(mat.total()*mat.elemSize())]);
                mat.get(0,0,serializedMat.bytes);
            }
            else if (serializedMat.getType()==1||
                    serializedMat.getType()==9||
                    serializedMat.getType()==17||
                    serializedMat.getType()==25)
            {
                serializedMat.setBytes(new byte[(int)(mat.total()*mat.elemSize())]);
                mat.get(0,0,serializedMat.bytes);
            }
            else if (serializedMat.getType()==2||
                    serializedMat.getType()==10||
                    serializedMat.getType()==18||
                    serializedMat.getType()==26)
            {
                serializedMat.setShorts(new short[(int)(mat.total()*mat.elemSize())]);
                mat.get(0,0,serializedMat.shorts);
            }
            else if (serializedMat.getType()==3||
                    serializedMat.getType()==11||
                    serializedMat.getType()==19||
                    serializedMat.getType()==27)
            {
                serializedMat.setShorts(new short[(int)(mat.total()*mat.elemSize())]);
                mat.get(0,0,serializedMat.shorts);
            }
            else if (serializedMat.getType()==4||
                    serializedMat.getType()==12||
                    serializedMat.getType()==20||
                    serializedMat.getType()==28)
            {
                serializedMat.setInts(new int[(int)(mat.total()*mat.elemSize())]);
                mat.get(0,0,serializedMat.ints);
            }
            else if (serializedMat.getType()==5||
                    serializedMat.getType()==13||
                    serializedMat.getType()==21||
                    serializedMat.getType()==29)
            {
                serializedMat.setFloats(new float[(int)(mat.total()*mat.elemSize())]);
                mat.get(0,0,serializedMat.floats);
            }
            else if (serializedMat.getType()==6||
                    serializedMat.getType()==14||
                    serializedMat.getType()==22||
                    serializedMat.getType()==30)
            {
                serializedMat.setDoubles(new double[(int)(mat.total()*mat.elemSize())]);
                mat.get(0,0,serializedMat.doubles);
            }
    
    //        return "";
            Gson gson = new Gson();
            return gson.toJson(serializedMat);
        }
    
        public static Mat DeserializeToMat(String json)
        {
            Gson gson = new Gson();
            SerializedMat serializedMat = gson.fromJson(json, SerializedMat.class);
            Mat mat = new Mat(serializedMat.getRows(),serializedMat.getCols(),serializedMat.getType());
    
            if (serializedMat.getType()==0||
                    serializedMat.getType()==8||
                    serializedMat.getType()==16||
                    serializedMat.getType()==24)
            {
                mat.put(0,0,serializedMat.getBytes());
            }
            else if (serializedMat.getType()==1||
                    serializedMat.getType()==9||
                    serializedMat.getType()==17||
                    serializedMat.getType()==25)
            {
                mat.put(0,0,serializedMat.getBytes());
            }
            else if (serializedMat.getType()==2||
                    serializedMat.getType()==10||
                    serializedMat.getType()==18||
                    serializedMat.getType()==26)
            {
                mat.put(0,0,serializedMat.getShorts());
            }
            else if (serializedMat.getType()==3||
                    serializedMat.getType()==11||
                    serializedMat.getType()==19||
                    serializedMat.getType()==27)
            {
                mat.put(0,0,serializedMat.getShorts());
            }
            else if (serializedMat.getType()==4||
                    serializedMat.getType()==12||
                    serializedMat.getType()==20||
                    serializedMat.getType()==28)
            {
                mat.put(0,0,serializedMat.getInts());
            }
            else if (serializedMat.getType()==5||
                    serializedMat.getType()==13||
                    serializedMat.getType()==21||
                    serializedMat.getType()==29)
            {
                mat.put(0,0,serializedMat.getFloats());
            }
            else if (serializedMat.getType()==6||
                    serializedMat.getType()==14||
                    serializedMat.getType()==22||
                    serializedMat.getType()==30)
            {
                mat.put(0,0,serializedMat.getDoubles());
            }
    
            return mat;
        }
    
        private static class SerializedMat
        {
            byte[] bytes;
            short[] shorts;
            int[] ints;
            float[] floats;
            double[] doubles;
    
            int type;
            int rows;
            int cols;
    
            byte[] getBytes()
            {
                return bytes;
            }
    
            void setBytes(byte[] bytes)
            {
                this.bytes = bytes;
            }
    
            short[] getShorts()
            {
                return shorts;
            }
    
            void setShorts(short[] shorts)
            {
                this.shorts = shorts;
            }
    
            int[] getInts()
            {
                return ints;
            }
    
            void setInts(int[] ints)
            {
                this.ints = ints;
            }
    
            float[] getFloats()
            {
                return floats;
            }
    
            void setFloats(float[] floats)
            {
                this.floats = floats;
            }
    
            double[] getDoubles()
            {
                return doubles;
            }
    
            void setDoubles(double[] doubles)
            {
                this.doubles = doubles;
            }
    
            int getType()
            {
                return type;
            }
    
            void setType(int type)
            {
                this.type = type;
            }
    
            int getRows()
            {
                return rows;
            }
    
            void setRows(int rows)
            {
                this.rows = rows;
            }
    
            int getCols()
            {
                return cols;
            }
    
            void setCols(int cols)
            {
                this.cols = cols;
            }
    
            SerializedMat()
            {
            }
        }
    }
    

    And you can store using tinyDB like below

    String kp_to_json=SerializeTheMat.keypointsToJson(kp_ref);
    String descriptors =  SerializeTheMat.SerializeFromMat(data);
    
    tinyDB.putString("DESC", descriptors);
    tinyDB.putString("KP", kp_to_json);
    

    And get it back like follows:

    data = SerializeTheMat.DeserializeToMat(tinyDB.getString("DESC"));
    
    kp_ref = SerializeTheMat.keypointsFromJson(tinyDB.getString("KP"));
    

    For storing them locally you can write JSON file from those string and read those JSON files whenever needed.

    THANKS