Question

This is my jni file , native.cpp

    extern "C"
 Java_org_opencv_samples_NativeActivity_CvNativeActivity_CannyJNI(
        JNIEnv* env, jobject thiz,
        jint height, jint width, jintArray in, jintArray out)
{
    //get the data pointer.
    jint* _in = env->GetIntArrayElements(in, 0);
    jint* _out = env->GetIntArrayElements(out, 0);


    //Build the Mat structure for input data
    Mat mSrc(height, width, CV_8UC4, (unsigned char *)_in);
    //Build the Mat structure for output data
    Mat bgr(height, width, CV_8UC4, (unsigned char *)_out);

    //Convert Mat to IplImage
    IplImage mSrcImg = mSrc;
    IplImage mOutImg = bgr;

    //Create the gray image for input data.
    IplImage * mSrcGrayImg = cvCreateImage(cvGetSize(&mSrcImg), mSrcImg.depth, 1);
    IplImage * mOutGrayImg = cvCreateImage(cvGetSize(&mSrcImg), mSrcImg.depth, 1);

    IplImage *b,*g,*r;
    b = cvCreateImage( cvGetSize(mSrcGrayImg), 8, 1 );
    g = cvCreateImage( cvGetSize(mSrcGrayImg), 8, 1 );
    r = cvCreateImage( cvGetSize(mSrcGrayImg), 8, 1 ) ;

    cvSplit(&mSrcImg, b, g, r, 0 );
    cvEqualizeHist( b, b );
    cvEqualizeHist( g, g );
    cvEqualizeHist( r, r );
    cvMerge(b,g,r,0,&mOutImg);
    //release the pointer.
    env->ReleaseIntArrayElements(in, _in, 0);
    env->ReleaseIntArrayElements(out, _out, 0);
    return true;
}

When i add these two lines my every jni part work for me

cvCvtColor(mOutGrayImg, mSrcGrayImg, CV_BGR2YCrCb);
cvCvtColor(mSrcGrayImg, &mOutImg , CV_YCrCb2BGR);

like from above code when i add

cvMerge(b,g,r,0,mOutGrayImg);
cvCvtColor(mOutGrayImg, mSrcGrayImg, CV_BGR2YCrCb);
cvCvtColor(mSrcGrayImg, &mOutImg , CV_YCrCb2BGR);

it runs , and same like my other codes , can anyone please tell me Why and How ? and How i can get rid of these two lines and simply cvMerge(b,g,r,0,mOutGrayImg); this lines send the output image and how i can set the C++ interface for this code.

Here is my jave file contain CvNativeActivity.java

public class CvNativeActivity extends Activity implements CvCameraViewListener2
{   
    public native boolean BrightnessJNI(int width, int height, int [] mPhotoIntArray, int [] mCannyOutArray);

    static 
    {
        System.loadLibrary("native_activity");
    }
    /** Called when the activity is first created. */ 
    ImageView imageview_1;
    ImageView imageview_2;
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
         imageview_1=(ImageView) findViewById(R.id.imageView1);
         imageview_2=(ImageView) findViewById(R.id.imageView2);

        InputStream is;
        is = this.getResources().openRawResource(R.drawable.foot);
        Bitmap bmInImg = BitmapFactory.decodeStream(is);

        int [] mPhotoIntArray;
        int [] mCannyOutArray;

        mPhotoIntArray = new int[bmInImg.getWidth() * bmInImg.getHeight()];
        // Copy pixel data from the Bitmap into the 'intArray' array
        bmInImg.getPixels(mPhotoIntArray, 0, bmInImg.getWidth(), 0, 0, bmInImg.getWidth(), bmInImg.getHeight());

        //create the Brightness result buffer
        mCannyOutArray = new int[bmInImg.getWidth() * bmInImg.getHeight()];

        //
        // Do Brightness
        //
        BrightnessJNI(bmInImg.getHeight(), bmInImg.getWidth(), mPhotoIntArray, mCannyOutArray);

        //
        // Convert the result to Bitmap
        //
        Bitmap bmOutImg = Bitmap.createBitmap(bmInImg.getWidth(), bmInImg.getHeight(), Config.ARGB_8888);  
        bmOutImg.setPixels(mCannyOutArray, 0, bmInImg.getWidth(), 0, 0, bmInImg.getWidth(), bmInImg.getHeight());


        imageview_2.setImageBitmap(bmOutImg);

        //
        // Save the result to file
        //
        String extStorageDirectory = Environment.getExternalStorageDirectory().toString();
        String outFileName = extStorageDirectory + "/Brightness";

        OutputBitmapToFile(bmOutImg, outFileName);





    }

    void OutputBitmapToFile(Bitmap InBm, String Filename)
    {
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        InBm.compress(Bitmap.CompressFormat.PNG, 100, bytes);

        File f = new File(Filename);
        try
        {
            f.createNewFile();
            //write the bytes in file
            FileOutputStream fo = new FileOutputStream(f);
            fo.write(bytes.toByteArray());
        } 
        catch (Exception e) 
        {
            e.printStackTrace();
        }           
    }
}

Thanks

Was it helpful?

Solution

Well, I found the issue. It's not showing the image because you have put alpha channel as 0 in cvMerge. Bitmap is of RGBA format. And the alpha is 0. Hence complete black image.

Here's the C API implementation code. This works.

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

using namespace std;
using namespace cv;

extern "C"
{
    JNIEXPORT jint JNICALL 
    Java_com_fenchtose_equalizehist_EqActivity_eqhist(
            JNIEnv* env, jobject,
            jint width, jint height, jintArray in, jintArray out)
    {
        jint* _in = env->GetIntArrayElements(in, 0);
        jint* _out = env->GetIntArrayElements(out, 0);

        Mat mSrc(height, width, CV_8UC4, (unsigned char*)_in);
        Mat bgra(height, width, CV_8UC4, (unsigned char*)_out);

        IplImage mSrcImg = mSrc;
        IplImage mOutImg = bgra;

        IplImage *b, *g, *r, *a;

        b = cvCreateImage(cvSize(width, height), mSrcImg.depth, 1);
        g = cvCreateImage(cvSize(width, height), mSrcImg.depth, 1);
        r = cvCreateImage(cvSize(width, height), mSrcImg.depth, 1);
        a = cvCreateImage(cvSize(width, height), mSrcImg.depth, 1);

        cvSplit(&mSrcImg, b, g, r, a);
        cvEqualizeHist(b, b);
        cvEqualizeHist(g, g);
        cvEqualizeHist(r, r);

        cvMerge(b, g, r, a, &mOutImg); // merge alpha layer too
        jint retVal;
        int ret = 1;
        retVal = jint(retVal);

        env->ReleaseIntArrayElements(in, _in, 0);
        env->ReleaseIntArrayElements(out, _out, 0);

        return retVal;


    }
}

OLD ANSWER: I copied your Java file. Made some minor changes. (Showed original image in imageView1, changed native function call).

Here's the JNI File.

#include <jni.h>
#include <stdio.h>
#include "opencv2/core/core.hpp"
#include <opencv2/imgproc/imgproc.hpp>
#include <vector>

using namespace std;
using namespace cv;

extern "C"
{
    JNIEXPORT jint JNICALL 
    Java_com_example_equalizehist_EqActivity_eqhist(
            JNIEnv* env, jobject,
            jint width, jint height, jintArray in, jintArray out)
    {
        jint* _in = env->GetIntArrayElements(in, 0);
        jint* _out = env->GetIntArrayElements(out, 0);

        Mat mSrc(height, width, CV_8UC4, (unsigned char*)_in);
        Mat bgra(height, width, CV_8UC4);

        vector<Mat> sChannels;
        split(mSrc, sChannels);

        for(int i=0; i<sChannels.size(); i++)
        {
            equalizeHist(sChannels[i], sChannels[i]);
        }

        merge(sChannels, bgra);

        for(int i=0; i<height; i++)
        {
            memcpy(&(_out[i*width]), &(bgra.data[i*bgra.step]), width*bgra.channels());
        }

        env->ReleaseIntArrayElements(in, _in, 0);
        env->ReleaseIntArrayElements(out, _out, 0);

        jint retVal;
        int ret = 1;
        retVal = jint(retVal);
        return retVal;
    }
}
  • Step1: Pass Pixel(int arrays) to native function.
  • Step2: Create Mat with input pixels.
  • Step3: Create an empty vector to hold each channel of mSrc Mat.
  • Step4: Split mSrc Mat to sChannels vector.
  • Step5: Apply equalizeHist function on each channel. Loop over sChannels vector.
  • Step6: Merge all the channels in bgra Mat.
  • Step7: Copy data of bgra Mat to the array of pixels. For this use memcpy. Iterate over each row of bgra Mat and copy data of each channel. This is CV_8UC4 Mat. Each channel will have data of 2 bytes. So Each pixel will contain 8 bytes of data.
  • Step8: Release arrays.

Here's the screenshot of the app.

enter image description here

I have put up this code on GitHub. You might want to check it if you run into any issues.

NOTE: If you're using this code, make sure that you declare the native function correctly.

If you don't want to use memcpy, you can directly allocate

#include <jni.h>
#include <stdio.h>
#include "opencv2/core/core.hpp"
#include <opencv2/imgproc/imgproc.hpp>
#include <vector>

using namespace std;
using namespace cv;

extern "C"
{
    JNIEXPORT jint JNICALL 
    Java_com_example_equalizehist_EqActivity_eqhist(
            JNIEnv* env, jobject,
            jint width, jint height, jintArray in, jintArray out)
    {
        jint* _in = env->GetIntArrayElements(in, 0);
        jint* _out = env->GetIntArrayElements(out, 0);

        Mat mSrc(height, width, CV_8UC4, (unsigned char*)_in);
        Mat bgra(height, width, CV_8UC4, (unsigned char*)_out);

        vector<Mat> sChannels;
        split(mSrc, sChannels);

        for(int i=0; i<sChannels.size(); i++)
        {
            equalizeHist(sChannels[i], sChannels[i]);
        }

        merge(sChannels, bgra);
        env->ReleaseIntArrayElements(in, _in, 0);
        env->ReleaseIntArrayElements(out, _out, 0);

        jint retVal;
        int ret = 1;
        retVal = jint(retVal);
        return retVal;
    }
}

Even this is working properly.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top