5

I am in the process of writing an Android application that uses JavaCV for some facial recognition. I have come across a slight problem where I need to convert from an org.opencv.core.Mat that the onCameraFrame(CvCameraViewFrame inputFrame) function returns to a org.bytedeco.javacpp.opencv_core.Mat that the org.bytedeco.javacpp.opencv_contrib.FaceRecognizer requires.

I have found similar questions here and here but neither got a working solution.

Community
  • 1
  • 1
Eduan Bekker
  • 411
  • 2
  • 7
  • 18
  • yea, sad topic- 2 java independant opencv wrappers, both basically incompatible. – berak Aug 27 '14 at 19:04
  • There must be some way. Writing a manual function to do it or something. – Eduan Bekker Aug 27 '14 at 19:10
  • "I am in the process of writing an Android application that uses JavaCV" : I stronly recommend that you use the official OpenCV Java API for new code. But if you really must do this, you probably need to to write some native code to do the conversion and call it via JNI, unless there is someway to coax the long result of OpenCV's `Mat.dataAddr()` into a bytdeco Pointer so you can pass it to the bytedeco Mat constructor. – Bull Aug 28 '14 at 01:58

2 Answers2

4

There's an easier, more efficient way documented at https://github.com/bytedeco/javacpp/issues/38#issuecomment-140728812, in short:

To JavaCPP/JavaCV:

Mat mat2 = new Mat((Pointer)null) { { address = mat.getNativeObjAddr(); } };

To official Java API of OpenCV:

Mat mat = new Mat(mat2.address());

EDIT: OpenCVFrameConverter now provides an easier and safer way to do this, for example:

OpenCVFrameConverter.ToMat converter1 = new OpenCVFrameConverter.ToMat();
OpenCVFrameConverter.ToOrgOpenCvCoreMat converter2 = new OpenCVFrameConverter.ToOrgOpenCvCoreMat();
Mat mat = ...;
org.opencv.core.Mat cvmat = converter2.convert(converter1.convert(mat));
Mat mat2 = converter2.convert(converter1.convert(cvmat));
Samuel Audet
  • 4,964
  • 1
  • 26
  • 33
1

You can use java.awt.image.BufferedImage as interface.

Just convert your org.opencv.core.Mat object to java.awt.image.BufferedImage and then take the result object to convert it to org.bytedeco.javacpp.opencv_core.Mat.

Now, these are the functions that you will need:

1) Convert org.opencv.core.Mat to java.awt.image.BufferedImage:

public BufferedImage matToBufferedImage(Mat frame) {       
        int type = 0;
        if (frame.channels() == 1) {
            type = BufferedImage.TYPE_BYTE_GRAY;
        } else if (frame.channels() == 3) {
            type = BufferedImage.TYPE_3BYTE_BGR;
        }
        BufferedImage image = new BufferedImage(frame.width() ,frame.height(), type);
        WritableRaster raster = image.getRaster();
        DataBufferByte dataBuffer = (DataBufferByte) raster.getDataBuffer();
        byte[] data = dataBuffer.getData();
        frame.get(0, 0, data);
        return image;
    }

2) Convert java.awt.image.BufferedImage to org.bytedeco.javacpp.opencv_core.Mat:

public Mat bufferedImageToMat(BufferedImage bi) {
        OpenCVFrameConverter.ToMat cv = new OpenCVFrameConverter.ToMat();
        return cv.convertToMat(new Java2DFrameConverter().convert(bi)); 
    }

Make sure to have all the necessary jars and imports.

You could go deeper into JNI stuff, but for test use cases, this should be enough.