码迷,mamicode.com
首页 > 其他好文 > 详细

JNI使用---如果我的cpp里边要使用opencv该怎么办呢?

时间:2015-07-07 14:50:10      阅读:126      评论:0      收藏:0      [点我收藏+]

标签:jni   opencv   c++   

本次需求与问题

我用javah生成.h头文件之后,要生成相应的cpp文件来实现头文件里边定义的方法。看到的很多示例都是在Java工程下边用命令行的方式来生成cpp的dll。
比如说http://blog.csdn.net/jianjian1992/article/details/46724043
那问题就来了,如果只是简单地使用c++来实现,那就在这个cpp里边写就好了,可是如果我要用到其它的库,比如说opencv,那该怎么办呢?在c++工程里边使用opencv可是需要各种配置的呀,现在我在一个java工程目录下,还只有一个cpp,这可肿么办啊!!

一个idea

An idea occurs to me:把这个.cpp和.h都加到一个已经配好的C++工程里边,然后在这个工程里边生成dll,这样可以吗?

实验

首先把.h和.cpp生成好来。

我的java文件如下:
import java.util.ArrayList;

public class MyNative
{
    static
    {
        System.loadLibrary( "face" );
    }
    public native static ArrayList<String> findCircles(String imgUrl, int left, int top, int right, int bottom);

    public static void main(String[] args){
        ArrayList<String> circles = MyNative.findCircles("D:/a.jpg", 1, 10, 30, 50);
        System.out.println(circles.size()); 
        for (int i = 0; i < circles.size(); i++){
            System.out.println(i +" : " + circles.get(i).toString());
        }
    }
}

生成的.h文件如下:
技术分享

然后准备一个C++工程

c_MyNative.h就是生成的头文件
findCircles.cpp则是对它的实现
技术分享
我们来观察一下命令行下生成dll的方式
cl -I c:/"Program Files"/Java/jdk1.6.0_10/include -I c:/"Program Files"/Java/jdk1.6.0_10/include/win32 -LD findCircles.cpp -FefindCircle.dll
里边加入了两个目录,分别是jdk里边的include以及它的子目录win32。
所以我便依葫芦画瓢,也在工程的包含目录里边把这两个目录加进去,如下图蓝框:
opencv等的包含目录也已经加在里边了。
技术分享
那按照惯例,库目录也得加是吧,囧,可我不知道jdk的库目录在哪啊,好吧,那就不管它,就只加包含目录看看行不行吧。

接下来就是实现cpp啦!

如下所示,我的函数主要功能是用对一幅图像找里边的一系列圆并返回,圆这里用字符串来表示。
这里得提一句:最初的时候我是用了Java的自定义类Circle,但是这个cpp到了c++工程里边,可就找不到我自定义的类了,所以最后就改用字符串来表示了。

findCircles.cpp

#include "c_MyNative.h"
#include <vector>
using namespace std;

//存储找到的圆
vector<char *> circles;
//list<int> lidata;
/*
 * Class:     c_MyNative
 * Method:    findCircles
 * Signature: (Ljava/lang/String;)Ljava/util/ArrayList;
 */
JNIEXPORT jobject JNICALL Java_c_MyNative_findCircles
  (JNIEnv *env, jclass thiz, jstring imgUrl, jint jLeft, jint jTop, jint jRight, jint jBottom)
  {
    //包围框的4个值  
    int left = jLeft, top = jTop, right = jRight, bottom = jBottom;

    //rtn为得到的char *类型的图像路径
    char* rtn = NULL;
    jclass clsstring = env->FindClass("java/lang/String");
    jstring strencode = env->NewStringUTF("utf-8");
    jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
    jbyteArray barr= (jbyteArray)env->CallObjectMethod(imgUrl, mid, strencode);
    jsize alen = env->GetArrayLength(barr);
    jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
    if (alen > 0)
    {
             rtn = (char*)malloc(alen + 1);
             memcpy(rtn, ba, alen);
             rtn[alen] = 0;
    }
    env->ReleaseByteArrayElements(barr, ba, 0);
    int intGetFromC = testaa(rtn);
    //下面不需要管它
    printf("received imgUrl is : %s\n", rtn);
    //find the ArrayList Object by its signature
    jclass cls_ArrayList = env->FindClass("java/util/ArrayList");
    //"<init>" denotes the construction method 
    //"()V" denotes no input parameters and the return type is void 
    jmethodID construct = env->GetMethodID(cls_ArrayList,"<init>","()V");  
    //generate an instance of ArrayList
    jobject obj_ArrayList = env->NewObject(cls_ArrayList,construct,"");  
    jmethodID arrayList_add = env->GetMethodID(cls_ArrayList,"add","(Ljava/lang/Object;)Z");  

    //下面进行数据填充与返回,我这里用的是一个vector<String>来保存所有圆的
    //首先对vector进行赋值
    int i;  
    for (i=0;i<5;i++){
        char cCircle[40];
        //每个Circle都用x:y:radius的形式保存
        sprintf(cCircle, "%d:%d:%d", i, i+1, i+2);
        //Circle cirTem(i,i+1,i+2);
        circles.push_back(cCircle);
    }
    //然后把vector里边的数据保存到返回的ArrayList里边,需要转化为jstring类型
    for(i=0;i<circles.size();i++){  
        //jobject circleObject = env->NewObject(circleClass,construct_circle);
        char *cirTem = circles[i];
        jstring jstrTem = (jstring)env->NewStringUTF(cirTem);  
        env->CallObjectMethod(obj_ArrayList, arrayList_add, jstrTem);  
    }  
    return obj_ArrayList;  
  }

里边有一句int intGetFromC = testaa(rtn);是用来测试opencv功能的,这个函数我定义在methods.h里边。
methods.h

#ifndef _METHOD_H_
#define _METHOD_H_
int testaa(char *name);
#endif

它的实现则放在faceExtract.cpp里边,这个函数具体如下:
输入一个图片路径,打开并显示它。

int testaa(char *name){
    IplImage *a = cvLoadImage(name);
    if (NULL == a){
        cerr << "Image path is not right\n";
        exit(-1);
    }
    else{
        cvNamedWindow("image");
        cvShowImage("image", a);
        waitKey(0);
        cvReleaseImage(&a);
    }
    return 1;
}

然后在工程里边生成dll

在项目的配置属性->常规处,我们把配置类型改为动态库。
技术分享
然后本地调试器调试一下,会弹窗一个错误,不管它,因为看输出是成功了的。
技术分享
在工程的debug目录下也确实生成了dll
技术分享
然后把它拷贝到Java项目里边

让我试试结果

技术分享
在java里边run一下,图片显示出来啦,结果输出也正确哦!
哈哈哈,实验成功啦!
技术分享
技术分享

版权声明:本文为博主原创文章,未经博主允许不得转载。

JNI使用---如果我的cpp里边要使用opencv该怎么办呢?

标签:jni   opencv   c++   

原文地址:http://blog.csdn.net/jianjian1992/article/details/46788087

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!