JavaWeb開發利用JNI調用C++代碼生成的dll進行圖像二值化處理並保存

使用JNI進行Java與C/C++語言混合編程----在Java中調用C/C++生成的DLL動態連接庫html

JNI是Java Native Interface的英文縮寫,
中文翻譯爲本地調用, 自從Java 1.1開始就成爲了Java標準的一部分.
Java調用C/C++大概有這樣幾個步驟java

  1. 編寫帶有native方法的Java類, 使用javac工具編譯Java類
  2. 使用javah來生成與native方法對應的頭文件
  3. 實現相應的頭文件, 並編譯爲動態連接庫(windows下是.dll, linux下是.so)

首先建立一個java工程,測試一下能不能調用openCV代碼:linux

public class hello {
            //不少教程會叫咱們聲明成static,可是我用的時候報錯了,因此我仍是    
            //不聲明成static了
            public native void sayHello(String path);
            public static void main(String[] args) {
            // TODO Auto-generated method stub
            hello h=new hello();
            //有時候會報錯說cannot load  xxx.dll
            //只須要將生成的xxx.dll放到這                
               //條語句輸出的路徑下便可
            System.out.println(System.getProperty("java.library.path"));
            //這裏調用的是java本地庫,TestAgain不加.dll。
            //怎樣生成.dll後面會介紹
            System.loadLibrary("TestAgain");
            
            h.sayHello("D:/images/5.jpg");
    
}

}ios

因爲我用的是myeclipse編寫和編譯的Java程序,c++

只須要配置一下就能夠用myeclipse生成xxx.h文件,web

在myclipse->run->External Tools->External Tools configurations編程

clipboard.png

通常須要選中一個工程才能run,而後就能夠生成xxx.h頭文件了
working Directory:${project_loc}
arguments:-v -classpath "${project_loc}/src" -d "${project_loc}/jni"
${java_type_name}segmentfault

製做.h文件還有一個更簡單的辦法,那就是直接cmd到當前工程的src目錄下,而後javah xxx(包名).xxx(類名),而後就能夠了,舉例假設包名爲com.action,類名爲upLoad,並且src目錄下
則應該是javah com.action.upLoad便可windows

這裏我也有些地方沒搞懂,由於我本身作這個項目的時候,用過jdk 1.6 1.7 1.8,最後使用的jdk1.6+tomcat6.0開發的,可是當我在location 中寫入jdk1.6 的bin/javah.exe,編譯個人javaweb工程時出現以下錯誤:數組

�����޷����� com.servlet.HandleImg
         δ�ҵ� com.servlet.HandleImg �����ļ�
javadoc: ���� - �Ҳ����� com.servlet.HandleImg��
[ Search Path: D:\jdk\jdk\jre\lib\resources.jar;D:\jdk\jdk\jre\lib\rt.jar;D:\jdk\jdk\jre\lib\sunrsasign.jar;D:\jdk\jdk\jre\lib\jsse.jar;D:\jdk\jdk\jre\lib\jce.jar;D:\jdk\jdk\jre\lib\charsets.jar;D:\jdk\jdk\jre\lib\modules\jdk.boot.jar;D:\jdk\jdk\jre\classes\D:\MyEclipseProfessional2014\workspace\HandleImage/src ]
Error: δ����������ָ���κ��ࡣ�볢��ʹ�� -help��

所以我用的是我jdk1.7中bin/javah.exe生成的xxx.h頭文件,實在不行就只能下載兩個jdk了,知識水平有限,望有人能解決這個問題。

無論怎麼說,最終頭文件是生成了,xxx.h文件在當前工程jni文件夾下,以下圖:

clipboard.png

打開後

clipboard.png

而後就能夠開始寫c++代碼了
file->new ->project 選擇visual C++ 和win32 Console Application而後ok

clipboard.png

個人操做系統和myeclipse都是64位的,所以生成32位的dll,在myeclipse中調用,會出現錯誤,這裏就須要配一下

clipboard.png

clipboard.png

clipboard.png

clipboard.png

而後就是配置opencv環境,我用的是opencv2.4.4,具體的配置過程,去百度opencv2.4.4配置教程,此次是在debug|x64下添加propertySheet了,

clipboard.png

繼續添加兩個路徑:C:Program FilesJavajdk1.7.0_80include和C:Program FilesJavajdk1.7.0_80includewin32,目的是爲了引入三個頭文件jni.h和jni_md.h還有jawt_md.h

clipboard.png

再就是右鍵工程 ->open folder in file explore 將上面生成的xxx.h文件copy到該文件夾下:

clipboard.png

而後HeaderFile裏面也放一份

clipboard.png

第二種引入改頭文件的方法是直接新建一個頭文件Test.h(名字能夠隨意取),而後將myEclipse中生成的頭文件的內容所有複製到Test.h中,而後在引用的時候將#include "com_Test_hello.h"改成#include "Test.h"便可

而後在source Files中新建TestAgain.cpp,代碼以下,

#include "com_Test_hello.h"
#include <iostream>  
#include <opencv2\highgui\highgui.hpp>  
#include <opencv2\core\core.hpp>  
#include <opencv2\imgproc\imgproc.hpp> 
#include <windows.h>

using namespace std;  
using namespace cv;


JNIEXPORT void JNICALL Java_com_Test_hello_sayHello
    (JNIEnv *env, jobject obj,jstring string){
     const char* str = env->GetStringUTFChars(string, 0);
    char cap[128];
    strcpy(cap, str);
    env->ReleaseStringUTFChars(string, 0);
    int len=strlen(cap);
    Mat imag, result;
    imag = imread(str,0);   //將讀入的彩色圖像直接以灰度圖像讀入  
    //namedWindow("原圖", 1);  
  //  imshow("原圖", imag);  
    result = imag.clone();  
   //進行二值化處理,選擇30,200.0爲閾值  
    threshold(imag, result, 30, 200.0, CV_THRESH_BINARY);  
    //namedWindow("二值化圖像");  
   // imshow("二值化圖像", result); 
    imwrite(str,result);
    printf("圖像二值化成功!");
}

而後就能夠build->build solution
如何使用Debug生成的解決方案的話,上面的那些環境就應該是在Debug下屬性表裏面添加,並且生成的dll也是在Debug文件夾目錄下。
要是想用Release生成的話,同上步驟便可。

構建成功後能夠在這裏找到

clipboard.png

將.dll文件複製到以前Java代碼中System.out.println(System.getProperty("java.library.path"));這條語句輸出的路徑中任何一個文件夾下便可
最後回到myeclipse中運行Java程序,就能夠了
完成了這個調用後,就只須要將這個嵌入到javaweb工程中便可

有些時候調用dll須要返回int數組,或者字符串,我再分享這兩個方法
返回一個int數組
生成的頭文件用javah生成.h頭文件

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Test_floatArray */

#ifndef _Included_Test_floatArray
#define _Included_Test_floatArray
#ifdef __cplusplus
extern "C" {
#endif
    /*
    * Class:     Test_floatArray
    * Method:    haha
    * Signature: ()[I
    */
    JNIEXPORT jintArray JNICALL Java_Test_floatArray_haha
        (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif
#include "Test.h"
#include <iostream>
JNIEXPORT jintArray JNICALL Java_Test_floatArray_haha
(JNIEnv *env, jobject obj){
    //1.新建長度len數組
    jintArray jarr = env->NewIntArray(3);
    //2.獲取數組指針
    jint *arr = env->GetIntArrayElements(jarr, NULL);
    //3.賦值
    int i = 0;
    for (; i < 3; i++){
        arr[i] = i;
    }
    //4.釋放資源
    env->ReleaseIntArrayElements(jarr, arr, 0);
    //5.返回數組
    return jarr;
}

返回一個字符串型數組,首先須要用一個stojstring()函數,將c++的string類型轉換爲const char 類型,再從const char 轉化爲jstring類型,便可直接返回一個jstring類型

#include "test.h"
#include <iostream>
#include <string.h>
using namespace std;

jstring stoJstring(JNIEnv* env, const char* pat)
{
    jclass strClass = env->FindClass("Ljava/lang/String;");
    jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
    jbyteArray bytes = env->NewByteArray(strlen(pat));
    env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);
    jstring encoding = env->NewStringUTF("utf-8");
    return (jstring)env->NewObject(strClass, ctorID, bytes, encoding);
}

JNIEXPORT jstring JNICALL Java_com_action_upLoadAction_shibie
(JNIEnv *env, jobject obj, jstring path1, jstring path2, jstring path3){
    const char* str1 = env->GetStringUTFChars(path1, 0);
    const char* str2 = env->GetStringUTFChars(path2, 0);
    const char* str3 = env->GetStringUTFChars(path3, 0);

    printf("%s\n", str1);
    printf("%s\n", str2);
    printf("%s\n", str3);
    printf("你好\n");

    string str = "好\#";
    const char* chardata = str.c_str();
    
    jstring jstr = stoJstring(env, chardata);

    return jstr;
}

test.h文件內容以下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_action_upLoadAction */

#ifndef _Included_com_action_upLoadAction
#define _Included_com_action_upLoadAction
#ifdef __cplusplus
extern "C" {
#endif
    /*
    * Class:     com_action_upLoadAction
    * Method:    Contrast
    * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
    */
    JNIEXPORT void JNICALL Java_com_action_upLoadAction_Contrast
        (JNIEnv , jobject , jstring , jstring, jstring);
    JNIEXPORT jstring JNICALL Java_com_action_upLoadAction_shibie
        (JNIEnv *, jobject, jstring, jstring, jstring);
    

#ifdef __cplusplus
}
#endif
#endif

關於java web,推薦去看個人另外一篇文章:https://segmentfault.com/a/11...

而後關於有些方法須要返回某個參數如String,boolean等,能夠參考這篇文章:
http://www.cnblogs.com/icejoy...

相關文章
相關標籤/搜索