您的位置:首页 > 编程语言 > C语言/C++

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啦,找到它们然后添加就是啦!

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: