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

原创 2015年07月07日 13:08:20

本次需求与问题

我用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一下,图片显示出来啦,结果输出也正确哦!
哈哈哈,实验成功啦!
这里写图片描述
这里写图片描述

dll依赖项问题

java.lang.UnsatisfiedLinkError: D:\MyEclipse7workspace\Struts2\CFindCircles.dll: Can’t find dependent libraries
使用其它人编译给我的dll,然后出现了上面的问题,
原因是使用了本地没有的一些dll,所以首先需要使用dll依赖项工具找到我们需要添加的dll。
可以在http://download.csdn.net/detail/zslenglish/4116558
下载工具。
打开工具之后open自己的dll,之后会如下图显示它所依赖的dll。
图中黄色问号标注的dll项就是所缺少的dll啦,找到它们然后添加就是啦!
这里写图片描述

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

相关文章推荐

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

本次需求与问题我用javah生成.h头文件之后,要生成相应的cpp文件来实现头文件里边定义的方法。看到的很多示例都是在Java工程下边用命令行的方式来生成cpp的dll。 比如说http://blo...

怎么使用wireshark

原文地址:http://www.9upk.com/article/2537.html wireshark是非常流行的网络封包分析软件,功能十分强大。可以截取各种网络封包,显示网络封包的详细信息...

我是如何成为一名python大咖的?

人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..

如何在Eclipse中使用aliyunMaven库添加Jar包

如何在Eclipse中添加aliyunMaven库 首先打开Eclipse 在搜索框中输入Maven 单击OK后,出现下面这个窗口 打开浏览器,粘贴上一步复制的URL到地址栏 打开网站...

iscroll4如何使用,iscroll使用实例

所有资讯 var myScroll, pullDownEl, pullDownOffset, pullUpEl, pullUpO...

Maven 使用介绍

Maven 使用介绍 创建project 先去官方网站下载一个最新版本http://maven.apache.org/download.cgi. 下载后解压,使用之前最好先将maven...

欢迎使用CSDN-markdown编辑器

欢迎使用Markdown编辑器写博客本Markdown编辑器使用[StackEdit][6]修改而来,用它写博客,将会带来全新的体验哦: Markdown和扩展Markdown简洁的语法 代码块高亮 ...

Printf的格式

为了以防忘记。。。 int printf(const char *format,[argument]); format 参数输出的格式,定义格式为:%[flags][width][.perc][F...

Git使用教程

转载至云溪的博客 Git使用教程  一:Git是什么?        Git是目前世界上最先进的分布式版本控制系统。 二:SVN与Git的最主要的区别?       ...

算法该怎么用呢

上周没有怎么刷题,感觉整个人都变水了。 今天写了一个水题,然而,我意识到了自己是有多么水,感觉自己完全没有脱离初学者的程度。然而q神一年都快进final了,想想自己,真的是渣渣。 题外话不多说了,...

为什么在SVN里要使用tags/branchs/trunk

为什么在SVN里要使用tags/branchs/trunk
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)