0

I've tried to serialize a map of pairs and obtained an exception as below:

 java.io.NotSerializableException: org.opencv.core.Mat

Is there some kind of way to serialize this?

1
  • The following SO answer has information concerning getting a Mat into Java primitives, which of course are serializable: stackoverflow.com/a/44089416/897007 Commented May 23, 2017 at 14:41

4 Answers 4

3

I made some improvments from here. Tested and working SerializationUtils class here

public static String matToJson(Mat mat){
    JsonObject obj = new JsonObject();

    if(mat.isContinuous()){
        int cols = mat.cols();
        int rows = mat.rows();
        int elemSize = (int) mat.elemSize();
        int type = mat.type();

        obj.addProperty("rows", rows);
        obj.addProperty("cols", cols);
        obj.addProperty("type", type);

        // We cannot set binary data to a json object, so:
        // Encoding data byte array to Base64.
        String dataString;

        if( type == CvType.CV_32S || type == CvType.CV_32SC2 || type == CvType.CV_32SC3 || type == CvType.CV_16S) {
            int[] data = new int[cols * rows * elemSize];
            mat.get(0, 0, data);
            dataString = new String(Base64.encodeBase64(SerializationUtils.toByteArray(data)));
        }
        else if( type == CvType.CV_32F || type == CvType.CV_32FC2) {
            float[] data = new float[cols * rows * elemSize];
            mat.get(0, 0, data);
            dataString = new String(Base64.encodeBase64(SerializationUtils.toByteArray(data)));
        }
        else if( type == CvType.CV_64F || type == CvType.CV_64FC2) {
            double[] data = new double[cols * rows * elemSize];
            mat.get(0, 0, data);
            dataString = new String(Base64.encodeBase64(SerializationUtils.toByteArray(data)));
        }
        else if( type == CvType.CV_8U ) {
            byte[] data = new byte[cols * rows * elemSize];
            mat.get(0, 0, data);
            dataString = new String(Base64.encodeBase64(data));
        }
        else {

            throw new UnsupportedOperationException("unknown type");
        }
        obj.addProperty("data", dataString);

        Gson gson = new Gson();
        String json = gson.toJson(obj);

        return json;
    } else {
        System.out.println("Mat not continuous.");
    }
    return "{}";
}

public static Mat matFromJson(String json){


    JsonParser parser = new JsonParser();
    JsonObject JsonObject = parser.parse(json).getAsJsonObject();

    int rows = JsonObject.get("rows").getAsInt();
    int cols = JsonObject.get("cols").getAsInt();
    int type = JsonObject.get("type").getAsInt();

    Mat mat = new Mat(rows, cols, type);

    String dataString = JsonObject.get("data").getAsString();
    if( type == CvType.CV_32S || type == CvType.CV_32SC2 || type == CvType.CV_32SC3 || type == CvType.CV_16S) {
        int[] data = SerializationUtils.toIntArray(Base64.decodeBase64(dataString.getBytes()));
        mat.put(0, 0, data);
    }
    else if( type == CvType.CV_32F || type == CvType.CV_32FC2) {
        float[] data = SerializationUtils.toFloatArray(Base64.decodeBase64(dataString.getBytes()));
        mat.put(0, 0, data);
    }
    else if( type == CvType.CV_64F || type == CvType.CV_64FC2) {
        double[] data = SerializationUtils.toDoubleArray(Base64.decodeBase64(dataString.getBytes()));
        mat.put(0, 0, data);
    }
    else if( type == CvType.CV_8U ) {
        byte[] data = Base64.decodeBase64(dataString.getBytes());
        mat.put(0, 0, data);
    }
    else {

        throw new UnsupportedOperationException("unknown type");
    }
    return mat;
}
Sign up to request clarification or add additional context in comments.

4 Comments

base64 encoding for image is gross.
Actually this is not image, feature.
Thanks for your code. Converting to json seems fine solution for me
Is this working in Android? I cant make it work in Android.
3

no, not so easy.

the actual data is held inside the c++ native so, so your serialize() won't reach into that.

what you can do:

Mat mat = ...
byte[] bytes = new byte[mat.total()*mat.elemSize()];
mat.get(0,0,bytes);
// now somehow save mat.type(), mat.rows(), mat.cols() and the bytes, later restore it:
Mat m2 = new Mat(rows,cols,type);
m2.put(0,0, bytes);

1 Comment

Is any other easy way to make something like database and store there all Mat objects I have?
0

I changed others code ,and it seems work. Hope it can help.

 public static byte[] serializeMat(Mat mat) {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            try {
                float[] data = new float[(int) mat.total() * mat.channels()];
                mat.get(0, 0, data);
                ObjectOutput out = new ObjectOutputStream(bos);
                out.writeObject(data);
                out.close();
                // Get the bytes of the serialized object
                byte[] buf = bos.toByteArray();
                return buf;
            } catch (IOException ioe) {
                ioe.printStackTrace();
                return null;
            }
        }

Comments

0

You can dump the contents to a String a serialize that, like so:

Mat mat = new Mat();
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
String json = ow.writeValueAsString(mat.dump());

1 Comment

What about deserialize this?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.