如何在Android Activity中调用Jni对象? [英] How to call Jni object in Android Activity?

查看:201
本文介绍了如何在Android Activity中调用Jni对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作文档扫描仪。我正在使用opencv进行图像处理。在相机视图中,我是最大轮廓上的矩形。处理用Native-lib.cpp编写的部分。它正确地检测最大轮廓。现在我想只捕获用native-lib.cpp编写的boudingRect。所以我想在java类中使用native-lib对象。帮助实现这一点。



Native-lib.cpp

  externC
JNIEXPORT void JNICALL
Java_prisca_ctest_OpenCvCamera_doWithMat(JNIEnv * env,jobject instance,jlong​​ matAddrGr,
jlong​​ matAddrRgba){
try {
Mat& image = *(Mat *)matAddrRgba;
Rect bounding_rect;

Mat thr(image.rows,image.cols,CV_8UC1);
cvtColor(image,thr,CV_BGR2GRAY); //转换为灰色
阈值(thr,thr,150,255,THRESH_BINARY + THRESH_OTSU); //阈值灰色

向量< vector< Point> >轮廓; //用于存储轮廓的矢量
vector< Vec4i>层次结构;
findContours(thr,contours,hierarchy,CV_RETR_CCOMP,
CV_CHAIN_APPROX_SIMPLE); //在图像中找到轮廓
sort(contours.begin(),contours.end(),
compareContourAreas); //存储最大轮廓的索引
bounding_rect = boundingRect((const _InputArray&)contours [0]);

矩形(image,bounding_rect,Scalar(250,250,250),5);
} catch(int a){

}
}

活动

  protected void onCreate(@Nullable Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.cam);
mOpenCvCameraView =(JavaCameraView)findViewById(R.id.tutorial1_activity_java_surface_view);
mOpenCvCameraView.setVisibility(View.VISIBLE);

mOpenCvCameraView.setCvCameraViewListener(this);
btnCapture =(Button)findViewById(R.id.btnCapture);
btnCapture.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view){
String timestamp = new SimpleDateFormat(ddMMyyyy_HHmmss,Locale.US ).format(new Date());
文件imgFolder =新文件(FILE_LOCATION);
imgFolder.mkdir();
文件图像=新文件(imgFolder,扫描+时间戳+.jpg);
String fileName = FILE_LOCATION +
/ Scan+ timestamp +.jpg;
Toast.makeText(OpenCvCamera.this,image +saved, Toast.LENGTH_SHORT)。show();
Imgcodecs.imwrite(fileName,mRgba);
}
});
}

@Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame){
//输入框架具有RGBA格式
mRgba = inputFrame.rgba( );
mGray = inputFrame.gray();
doWithMat(mGray.getNativeObjAddr(),mRgba.getNativeObjAddr());
返回mRgba;

}

我应该在上面添加什么?Imgcodecs .imwrite(fileName,mRgba)裁剪矩阵并仅保存 boundingRect part?



<可能我必须在 imwrite 之前写这个 -

  Mat裁剪= mRgba.submat(bounding_rect); 
Imgcodecs.imwrite(fileName,cropped);

但是我不能从Native-lib调用bounding_rect。怎么称呼它?
提前感谢你:)

解决方案

你可以收到 org.opencv.core.Rect 来自 native-lib 。最简单的方法是更改​​本机方法签名, doWithMat(),如下所示:

  private org.opencv.core.Rect mBoundingRect; 

@Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame){
//输入帧具有RGBA格式
mRgba = inputFrame.rgba();
mGray = inputFrame.gray();
mBoundingRect = doWithMat(mGray.getNativeObjAddr(),mRgba.getNativeObjAddr());
返回mRgba;
}






  externC
JNIEXPORT jobject JNICALL
Java_prisca_ctest_OpenCvCamera_doWithMat(JNIEnv * env,jobject instance,
jlong​​ matAddrGr,jlong​​ matAddrRgba){

Mat& image = *(Mat *)matAddrRgba;
Rect bounding_rect;

Mat thr(image.rows,image.cols,CV_8UC1);
cvtColor(image,thr,CV_BGR2GRAY); //转换为灰色
阈值(thr,thr,150,255,THRESH_BINARY + THRESH_OTSU); //阈值灰色

向量< vector< Point> >轮廓; //用于存储轮廓的矢量
vector< Vec4i>层次结构;
findContours(thr,contours,hierarchy,CV_RETR_CCOMP,
CV_CHAIN_APPROX_SIMPLE); //在图像中找到轮廓
sort(contours.begin(),contours.end(),
compareContourAreas); //存储最大轮廓的索引
bounding_rect = boundingRect((const _InputArray&)contours [0]);

矩形(image,bounding_rect,Scalar(250,250,250),5);

jclass rectClass = env-> FindClass(org / opencv / core / Rect);
jmethodID rectCtorID = env-> GetMethodID(rectClass,< init>,(IIII)V);
return env-> NewObject(rectClass,rectCtorID,bounding_rect.x,bounding_rect.y,bounding_rect.width,bounding_rect.height);
}

如你所见,我删除了试试..从本机代码中捕获;我不认为它真的有用,特别是当你试图捕获一个int而不是异常时。



注意提取 rectClass 并且 rectCtorID 是昂贵的操作,因此缓存这些值是明智的:

  static jclass rectClass = nulltr ; 
ststic jmethodID rectCtorID = 0;
if(rectCtorID == 0){
rectClass = env-> NewGlobalRef(env-> FindClass(org / opencv / core / Rect));
rectCtorID = env-> GetMethodID(rectClass,< init>,(IIII)V);
}

请注意,我们需要对Java类的全局引用,但方法ID是只是一个int。






我建议的另一个优化是使用 matAddrGr 。如果我理解正确,OpenCV将为 onCameraFrame()准备两个矩阵,因此您可能不需要将RGB转换为灰色。


I am making an Document Scanner. I'm using opencv for image processing. In camera view i'm bounding rectangle on largest contour. Processing part written in Native-lib.cpp. It is detecting largest contour properly. And now i want to capture only boudingRect which is written in native-lib.cpp. So i want object of native-lib in java class. help to get that.

Native-lib.cpp

extern "C"
JNIEXPORT void JNICALL
Java_prisca_ctest_OpenCvCamera_doWithMat(JNIEnv *env, jobject instance, jlong matAddrGr,
                                     jlong matAddrRgba) {
try {
    Mat &image = *(Mat *) matAddrRgba;
    Rect bounding_rect;

    Mat thr(image.rows, image.cols, CV_8UC1);
    cvtColor(image, thr, CV_BGR2GRAY); //Convert to gray
    threshold(thr, thr, 150, 255, THRESH_BINARY + THRESH_OTSU); //Threshold the gray

    vector<vector<Point> > contours; // Vector for storing contour
    vector<Vec4i> hierarchy;
    findContours(thr, contours, hierarchy, CV_RETR_CCOMP,
                 CV_CHAIN_APPROX_SIMPLE); // Find the contours in the image
    sort(contours.begin(), contours.end(),
         compareContourAreas);            //Store the index of largest contour
    bounding_rect = boundingRect((const _InputArray &) contours[0]);

rectangle(image, bounding_rect, Scalar(250, 250, 250) , 5);
} catch (int a) {

}
}

Activity

 protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.cam);
    mOpenCvCameraView = (JavaCameraView) findViewById(R.id.tutorial1_activity_java_surface_view);
    mOpenCvCameraView.setVisibility(View.VISIBLE);

    mOpenCvCameraView.setCvCameraViewListener(this);
    btnCapture = (Button) findViewById(R.id.btnCapture);
    btnCapture.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            String timestamp = new SimpleDateFormat("ddMMyyyy_HHmmss", Locale.US).format(new Date());
            File imgFolder = new File(FILE_LOCATION);
            imgFolder.mkdir();
            File image = new File(imgFolder, "Scan" + timestamp + ".jpg");
            String fileName = FILE_LOCATION +
                    "/Scan" + timestamp + ".jpg";
            Toast.makeText(OpenCvCamera.this, image + " saved", Toast.LENGTH_SHORT).show();
            Imgcodecs.imwrite(fileName, mRgba);
        }
    }) ;
}

@Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
    // input frame has RGBA format
    mRgba = inputFrame.rgba();
    mGray = inputFrame.gray();
    doWithMat(mGray.getNativeObjAddr(), mRgba.getNativeObjAddr());
    return mRgba;

}

What should i add above Imgcodecs.imwrite(fileName, mRgba) to crop the matrix and save only boundingRect part?

probably I have to write this before imwrite -

Mat cropped = mRgba.submat( bounding_rect );
            Imgcodecs.imwrite(fileName, cropped);

But i cannot call bounding_rect from Native-lib. How to call it ? Thank u in advance :)

解决方案

You can receive org.opencv.core.Rect from native-lib. The easiest way is to change your native method signature, doWithMat() like this:

private org.opencv.core.Rect mBoundingRect;

@Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
    // input frame has RGBA format
    mRgba = inputFrame.rgba();
    mGray = inputFrame.gray();
    mBoundingRect = doWithMat(mGray.getNativeObjAddr(), mRgba.getNativeObjAddr());
    return mRgba;
}


extern "C"
JNIEXPORT jobject JNICALL
Java_prisca_ctest_OpenCvCamera_doWithMat(JNIEnv *env, jobject instance,
        jlong matAddrGr, jlong matAddrRgba) {

    Mat &image = *(Mat *) matAddrRgba;
    Rect bounding_rect;

    Mat thr(image.rows, image.cols, CV_8UC1);
    cvtColor(image, thr, CV_BGR2GRAY); // Convert to gray
    threshold(thr, thr, 150, 255, THRESH_BINARY + THRESH_OTSU); //Threshold the gray

    vector<vector<Point> > contours; // Vector for storing contour
    vector<Vec4i> hierarchy;
    findContours(thr, contours, hierarchy, CV_RETR_CCOMP,
        CV_CHAIN_APPROX_SIMPLE); // Find the contours in the image
    sort(contours.begin(), contours.end(),
        compareContourAreas);    // Store the index of largest contour
    bounding_rect = boundingRect((const _InputArray &) contours[0]);

    rectangle(image, bounding_rect, Scalar(250, 250, 250) , 5);

    jclass rectClass = env->FindClass("org/opencv/core/Rect");
    jmethodID rectCtorID = env->GetMethodID(rectClass, "<init>", "(IIII)V");
    return env->NewObject(rectClass, rectCtorID, bounding_rect.x, bounding_rect.y, bounding_rect.width, bounding_rect.height);
}

As you can see, I removed try ... catch from the native code; I don't think it can really help, especially when you try to catch an int, instead of exception.

Note that extraction of rectClass and rectCtorID are expensive operations, therefore it's smart to cache these values:

static jclass rectClass = nulltr;
ststic jmethodID rectCtorID = 0;
if (rectCtorID == 0) {
    rectClass = env->NewGlobalRef(env->FindClass("org/opencv/core/Rect"));
    rectCtorID = env->GetMethodID(rectClass, "<init>", "(IIII)V");
}

Note that we need a global reference to Java class, but the method ID is just an int.


Another optimization that I can suggest is to use matAddrGr. If I understand correctly, OpenCV will prepare both matrices for onCameraFrame(), so you there is probably no need to convert RGB to gray.

这篇关于如何在Android Activity中调用Jni对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆