使用JNI進行Java與C/C++語言混合編程----在Java中調用C/C++生成的DLL動態鏈接庫
JNI是Java Native Interface的英文縮寫,
中文翻譯為本地調用, 自從Java 1.1開始就成為了Java標準的一部分.
Java調用C/C++大概有這樣幾個步驟
編寫帶有native方法的Java類, 使用javac工具編譯Java類
使用javah來生成與native方法對應的頭文件
實現相應的頭文件, 并編譯為動態鏈接庫(windows下是.dll, linux下是.so)
首先創建一個java工程,測試一下能不能調用openCV代碼:
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"); }
}
由于我用的是myeclipse編寫和編譯的Java程序,
只需要配置一下就可以用myeclipse生成xxx.h文件,
在myclipse->run->External Tools->External Tools configurations
一般需要選中一個工程才能run,然后就可以生成xxx.h頭文件了
working Directory:${project_loc}
arguments:-v -classpath "${project_loc}/src" -d "${project_loc}/jni"
${java_type_name}
制作.h文件還有一個更簡單的辦法,那就是直接cmd到當前工程的src目錄下,然后javah xxx(包名).xxx(類名),然后就可以了,舉例假設包名為com.action,類名為upLoad,而且src目錄下
則應該是javah com.action.upLoad即可
這里我也有些地方沒搞懂,因為我自己做這個項目的時候,用過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:jdkjdkjrelib esources.jar;D:jdkjdkjrelib t.jar;D:jdkjdkjrelibsunrsasign.jar;D:jdkjdkjrelibjsse.jar;D:jdkjdkjrelibjce.jar;D:jdkjdkjrelibcharsets.jar;D:jdkjdkjrelibmodulesjdk.boot.jar;D:jdkjdkjreclassesD:MyEclipseProfessional2014workspaceHandleImage/src ] Error: δ??????????????κ?????????? -help??
因此我用的是我jdk1.7中bin/javah.exe生成的xxx.h頭文件,實在不行就只能下載兩個jdk了,知識水平有限,望有人能解決這個問題。
不管怎么說,最終頭文件是生成了,xxx.h文件在當前工程jni文件夾下,如下圖:
打開后
然后就可以開始寫c++代碼了
file->new ->project 選擇visual C++ 和win32 Console Application然后ok
我的操作系統和myeclipse都是64位的,因此生成32位的dll,在myeclipse中調用,會出現錯誤,這里就需要配一下
然后就是配置opencv環境,我用的是opencv2.4.4,具體的配置過程,去百度opencv2.4.4配置教程,這次是在debug|x64下添加propertySheet了,
繼續添加兩個路徑:C:Program FilesJavajdk1.7.0_80include和C:Program FilesJavajdk1.7.0_80includewin32,目的是為了引入三個頭文件jni.h和jni_md.h還有jawt_md.h
再就是右鍵工程 ->open folder in file explore 將上面生成的xxx.h文件copy到該文件夾下:
然后HeaderFile里面也放一份
第二種引入改頭文件的方法是直接新建一個頭文件Test.h(名字可以隨意取),然后將myEclipse中生成的頭文件的內容全部復制到Test.h中,然后在引用的時候將#include "com_Test_hello.h"改為#include "Test.h"即可
然后在source Files中新建TestAgain.cpp,代碼如下,
#include "com_Test_hello.h" #include#include #include #include #include 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生成的話,同上步驟即可。
構建成功后可以在這里找到
將.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/* 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" #includeJNIEXPORT 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#include using namespace std; jstring stoJstring(JNIEnv* env, const char* pat) { jclass strClass = env->FindClass("Ljava/lang/String;"); jmethodID ctorID = env->GetMethodID(strClass, " ", "([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 ", str1); printf("%s ", str2); printf("%s ", str3); printf("你好 "); 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/* 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...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/70389.html
摘要:可惜收費的,今天要介紹的完美驗證碼識別系統是類似的免費產品。調用函數相當簡單的,對比復雜的參數,這個識別是相當的快捷。 此文已由作者徐迪授權網易云社區發布。 歡迎訪問網易云社區,了解更多網易技術產品運營經驗。 講到驗證碼識別,大家第一個可能想到tesseract。誠然,對于OCR而言,tesseract確實很強大,自帶的字模能識別絕大多數規整的中英文。但是驗證碼畢竟不是OCR。對于現在...
摘要:這是坐標百度,好像沒啥好研究的了,不過出于好奇還是想知道使用是如何做到把文字區域進行框選的,所以接下來我們就看看如何在上使用實現圖片中的文字框選。一些探索 最近下了幾個OCR的App(比如白描),發現可以選中圖片中的文字行逐行轉成文字,覺得很有意思(當然想用要花錢啦),想著自己研究一下實現原理,google之后,發現了兩個庫,一個是OpenCV,在機器視覺方面應用廣泛,圖像分析必備利器。另一...
閱讀 849·2023-04-25 21:21
閱讀 3231·2021-11-24 09:39
閱讀 3072·2021-09-02 15:41
閱讀 2001·2021-08-26 14:13
閱讀 1833·2019-08-30 11:18
閱讀 2775·2019-08-29 16:25
閱讀 510·2019-08-28 18:27
閱讀 1585·2019-08-28 18:17