JNI使用---如果我的cpp里边要使用opencv该怎么办呢?
2015-07-07 13:08
344 查看
本次需求与问题
我用javah生成.h头文件之后,要生成相应的cpp文件来实现头文件里边定义的方法。看到的很多示例都是在Java工程下边用命令行的方式来生成cpp的dll。比如说/article/7573681.html
那问题就来了,如果只是简单地使用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啦,找到它们然后添加就是啦!
相关文章推荐
- C语言之基本算法13—兑换硬币
- C语言之基本算法12—谁是冠军
- C语言之基本算法11—牛顿迭代法求平方根
- 【C++】用C或C++实现void reverse(char* str)函数,即反转一个null结尾的字符串
- C++中的priority_queue
- 【转】C++ bitset类的使用与简介
- C++纯虚函数 virtual =0
- 浅谈C/C++的浮点数在内存中的存储方式
- C++的输入输出
- VC++ 的MFC 和ATL 及COM 是什么?
- 最长共公共子序列和最长公共子串
- 黑马程序员——C语言基础---基础语法
- C++ strcat
- C++ vtable layout
- chapter16test7
- 《C语言及程序设计》实践参考——二进制文件浏览器
- 《C语言及程序设计》实践参考——间隔选职工
- C/C++语言获取系统时间的几种方式 !
- 《C语言及程序设计》实践参考——处理C语言源代码的程序
- 《C语言及程序设计》实践参考——用文本文件保存的学生名单