Search code examples
javaandroidc++opencvjava-native-interface

JNI CameraPreview draw Rectangle with opencv


I wanted to process in real time the CameraPreview generated in my application and as such I followed a tutorial to use JNI. I am a complete newbie when it comes to C/C++ and I wasn't able to find sufficient explanations. My actual code generates an imageView above the camerapreview and the result of the processing frames from the latter are put in the former with the method setPixels. The bitmap turns grey and when I try to draw a rectangle on it we can see the camerapreview instead of the color of the stroke.

#include <jni.h>

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc_c.h>
#include "opencv2/highgui/highgui.hpp"


using namespace std;
using namespace cv;

extern "C"
jboolean
Java_com_test_camera_CameraPreview_ImageProcessing(
        JNIEnv* env, jobject thiz,
        jint width, jint height,
        jbyteArray NV21FrameData, jintArray outPixels)
{
    jbyte * pNV21FrameData = env->GetByteArrayElements(NV21FrameData, 0);
    jint * poutPixels = env->GetIntArrayElements(outPixels, 0);

    Mat mGray(height, width, CV_8UC1, (unsigned char *)pNV21FrameData);
    Mat mResult(height, width, CV_8UC4, (unsigned char *)poutPixels);

    IplImage srcImg = mGray;
    IplImage ResultImg = mResult;

    cvCvtColor(&srcImg, &ResultImg, CV_GRAY2BGRA);

    cvRectangle(&ResultImg, cvPoint(100,10), cvPoint(200, 50), CV_RGB(0,0,0), 3, 8, 0);

    env->ReleaseByteArrayElements(NV21FrameData, pNV21FrameData, 0);
    env->ReleaseIntArrayElements(outPixels, poutPixels, 0);
    return true;
}

And the following result:

Rectangle in the top left corner Rectangle in the top left corner

I know that the camerapreview gives YUV format frames but in the tutorial I followed it wasn't a need to convert the YUV image to an RGB one. I tried to change the CV_GRAY2BGRA parameters by searching on the OpenCv doc but I only ended without the imageview been displayed. Is there a way to draw a rectangle on the image and return a colored image directly in JNI ?

Edit --------------------------------------------------------------

I found a way to do what I wanted thanks to your advice.I put it here if it can help someone !

I put this code in the method OnPreviewFrame of my CameraPreview.java :

 int width  = PreviewSizeWidth;
 int height = PreviewSizeHeight;

 if( mYuv != null ) mYuv.release();
 mYuv = new Mat( height + height/2, width, CvType.CV_8UC1 );
 mYuv.put( 0, 0, data );
 Mat mRgba = new Mat();

 Imgproc.cvtColor( mYuv, mRgba, Imgproc.COLOR_YUV2RGBA_NV21, 4 );

 Bitmap map = Bitmap.createBitmap( width, height, Bitmap.Config.ARGB_8888 );

 Imgproc.rectangle(mRgba, new Point(100, 50), new Point(200, 100), new Scalar(0, 255, 0, 255), 5);

 Utils.matToBitmap( mRgba, map );

 MyCameraPreview.setImageBitmap(map);
 mRgba.release();

Solution

  • Take a look here, at the method onYuvDataReceived, where I think it performs the conversion you are seeking.

    First you have to manipulate your YUV byte array, and then use then use the cvCvtColor(&srcImg, &ResultImg, CV_YUV2BGRA_NV21)