• JAVA调用C语言函数的封装过程


    背景

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

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

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

    实现过程

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

    package com.iflytek.research.yoloserver;
    
    /**
     * 对yolo9000的封装
     * <p>调用本地库来识别图片中的物体</p>
     * @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 <jni.h>
    /* 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!
    ",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!
    ",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 FilesJavajdk1.8.0_151include" -I "C:Program FilesJavajdk1.8.0_151includewin32" -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字符串。

  • 相关阅读:
    监控 SQL Server 的运行状况
    软件开发报价的计算方法
    PHP 正则表达式
    ObjectiveC编程语言简介
    iframe 自适应高度,无限级父框架
    分享iphone开发的好网站,希望大家也能提供一些分享下
    实战WebService I: XMLPRC篇(基于php)
    PHPPRC
    Objective C cocos2D场景切换方式总汇
    NoSQL数据存储引擎
  • 原文地址:https://www.cnblogs.com/ljgeng/p/10026338.html
Copyright © 2020-2023  润新知