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啦,找到它们然后添加就是啦!
这里写图片描述

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

Windows7下使用Dev-CPP 编译 JNI

新建Java工程 编写调用JNI的Java代码,在Windows下是调用 dll,但不用写在代码里 利用Javah工具对class生成对应的...
  • Vange
  • Vange
  • 2012年08月20日 17:49
  • 1014

使用zbar+opencv+cpp 进行二维码解析以及提高识别率

1.zbar的安装和基本使用 关于zbar的安装可以参考这一篇http://blog.csdn.net/felix86/article/details/41443741 VS下安装zbar可以下载zb...

android开发在jni中使用Opencv进行图像处理,环境搭建篇

1、准备工作:(1)JDK——官网下载,在系统

在Android中使用JNI调用Opencv本地代码 配置方式 边缘检测 范例代码

简介:本系列博客介绍了安卓开发环境的配置,和在安卓开发中,通过JNI调用本地C++代码,使用opencv进行开发处理,本地代码通过NDK进行编译。 参考链接:http://www.cnblog...

使用Java api 和 jni混合方式调用OpenCV

from: http://blog.csdn.net/lingyun_blog/article/details/50733331 [java] view plain copy "font-...

Android Studio中使用JNI调用OpenCV本地代码Canny 边缘检测

Android Studio中使用JNI调用OpenCV本地代码Canny 边缘检测

android jni中将大数据回调到java层的时候用法,比如视频流,音频流等,图片流等 比如我用ffmpeg解码好视频流,想送到java层使用opengGL进行显示,opencv进行人脸识别等等

android jni中将大数据回调到java层的时候用法,比如视频流,音频流等,图片流等 比如我用ffmpeg解码好视频流,想送到java层使用opengGL进行显示,opencv进行人脸识别等等j...

Android Studio如何在项目中使用jni以及OpenCV库

Android Studio如何在项目中使用jni以及OpenCV库由于公司这一个项目是将之前运行在Linux上的代码移植到Android上,所以需要学习使用jni将原来的C++代码打包成so库,然后...

Windows下使用android NDK(JNI)调用OpenCV本地代码——流程梳理

最近在弄把window下用 vs+opencv写的C代码算法打包成.so文件,供Android平台调用。从零学习Android环境的搭建,参考了各种大神的博客,使用ndk算是走通了一条路。 把整个过程...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:JNI使用---如果我的cpp里边要使用opencv该怎么办呢?
举报原因:
原因补充:

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