java c语言 %s_JAVA调用C语言函数的封装过程

背景

最近产品需要做一个物体识别的app demo, 咨询研究人员之后,得到开源的yolo9000可以满足需要,yolo中使用的darknet是C语言编写的,yolo9000编译之后本身提供了命令行模式来生成识别结果,默认的结果是识别后带有画框的图片,如图:

41401d71719f7ef9ca090db32d4075d8.png

图片中框体title即是识别的结果(只有英文),首先想到的是可以通过java执行本地命令的方式来生成图片,然后将图片以接口的方式传给app,但是app拿到图片后就只能直接展示给用户,无法再做如翻译等进一步的处理。

基于以上情况,我想到的解决方案是:对darknet源码进行改写,添加识别物体返回json数据(包含物体名称,坐标,识别百分比等)的函数,再利用Java可以调用本地函数的特性直接调用该函数。

实现过程

JAVA调用C方法获取识别结果,思路是这样的:将用户传来的图片放到一个临时目录中,然后调用C函数分析,得到结果后,返回给用户。所以先定义一个调用C得本地方法

package com.iflytek.research.yoloserver;

/**

* 对yolo9000的封装

*

调用本地库来识别图片中的物体

* @author ljgeng

*

*/

public class Yolo {

/**

* 物体识别,函数会从指定的路径读取图片解析

* @param imgPath 图片的路径

* @return 识别的结果,json 格式的文本

*/

public static native String predict(String imgPath);

}

定义好函数之后,利用javah 工具自动生成c语言的头文件。

javah com.iflytek.research.yoloserver.Yolo

运行后会生成一个com_iflytek_research_yoloserver_Yolo.h 文件,将文件导入C项目中

/* DO NOT EDIT THIS FILE - it is machine generated */

#include

/* Header for class com_iflytek_research_yoloserver_Yolo */

#ifndef _Included_com_iflytek_research_yoloserver_Yolo

#define _Included_com_iflytek_research_yoloserver_Yolo

#ifdef __cplusplus

extern "C" {

#endif

/*

* Class: com_iflytek_research_yoloserver_Yolo

* Method: predict

* Signature: (Ljava/lang/String;)Ljava/lang/String;

*/

JNIEXPORT jstring JNICALL Java_com_iflytek_research_yoloserver_Yolo_predict

(JNIEnv *, jclass, jstring);

#ifdef __cplusplus

}

#endif

#endif

在C项目中新建yolo.c, 引入刚刚的头文件,并实现predict方法

#include "com_iflytek_research_yoloserver_Yolo.h"

#include "stdio.h"

JNIEXPORT jstring JNICALL Java_com_iflytek_research_yoloserver_Yolo_predict

(JNIEnv * env, jclass jcs, jstring jstr){

const char * str = (*env)->GetStringUTFChars(env,jstr,0);

if (str == NULL) {

return NULL;

}

printf("%s!\n",str);

(*env)->ReleaseStringUTFChars(env, jstr, str);

char * jsonStr = "{\"semantic\":{\"slots\":{\"name\":\"张三\"}}, \"rc\":0, \"operation\":\"CALL\", \"service\":\"telephone\", \"text\":\"打电话给张三\"}";

return (*env)->NewStringUTF(env, jsonStr);

}

现在只是先跑通流程,所以在yolo.c中还没有真正调用object detection相关的方法,以下对predict函数的简单解释

const char * str = (*env)->GetStringUTFChars(env,jstr,0); // 调用jni 函数GetStringUTFChars 读取Java String 对象内容

printf("%s!\n",str); // 打印

return (*env)->NewStringUTF(env, jsonStr); // 调用jni函数NewStringUTF 返回一个Java String对象。

JNI 有不少函数,有兴趣可以去官网或者相关博客学习一下。

写好C代码之后,将其编译到动态库中,供Java调用,我使用的是window系统,于是安装了cygwin64,并带上gcc功能。

x86_64-w64-mingw32-gcc.exe -D __int64="long long" -I "C:\Program Files\Java\jdk1.8.0_151\include" -I "C:\Program Files\Java\jdk1.8.0_151\include\win32" -shared -o yolo.dll yolo.c -W

具体使用哪个gcc命令,看系统实际情况。成功后,生成的yolo.dll 拷贝到Java项目根目录,加载库后运行。

package com.iflytek.research.yoloserver;

/**

* 程序入口

*

*/

public class YoloServerApp {

static {

System.loadLibrary("yolo");

}

public static void main(String[] args) {

String re = Yolo.predict("你好");

System.out.println(re);

}

}

使用静态代码块先加载库,然后运行predict函数,成功返回了json字符串。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值