Unsatisfiedlinkerror Android用OpenALPRテストプロジェクト 質問する

Unsatisfiedlinkerror Android用OpenALPRテストプロジェクト 質問する

数日間、私は構築しようとしていますAndroid 向け OpenALPR サンプル プロジェクトビルドして起動しますが、それを認識するためにネイティブ メソッドを呼び出した後、例外が発生します。

java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:299)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352)
at java.util.concurrent.FutureTask.setException(FutureTask.java:219)
at java.util.concurrent.FutureTask.run(FutureTask.java:239)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
at java.lang.Thread.run(Thread.java:838)

Caused by: java.lang.UnsatisfiedLinkError: Native method not found: org.openalpr.AlprJNIWrapper.recognizeWithCountryRegionNConfig:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;
at org.openalpr.AlprJNIWrapper.recognizeWithCountryRegionNConfig(Native Method)
at org.openalpr.app.AlprFragment$AlprTask.doInBackground(AlprFragment.java:78)
at org.openalpr.app.AlprFragment$AlprTask.doInBackground(AlprFragment.java:1)
at android.os.AsyncTask$2.call(AsyncTask.java:287)
at java.util.concurrent.FutureTask.run(FutureTask.java:234)
... 4 more

何もできない、いつも現れる。

アプリケーション.mk

APP_ABI := armeabi-v7a
APP_CPPFLAGS := -frtti -fexceptions
APP_STL := gnustl_static

Android.mk あらゆる試みの末

LOCAL_PATH := $(call my-dir)
LIB_PATH := $(LOCAL_PATH)/../libs/armeabi-v7a

include $(CLEAR_VARS)

LOCAL_MODULE := leptonica
LOCAL_SRC_FILES := 3rdparty/liblept.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)

LOCAL_MODULE := tesseract
LOCAL_SRC_FILES := 3rdparty/libtess.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)

LOCAL_MODULE := simpleini
LOCAL_SRC_FILES := 3rdparty/libsimpleini.a
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)

LOCAL_MODULE := support
LOCAL_SRC_FILES := 3rdparty/libsupport.a
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)

LOCAL_MODULE := openalpr
LOCAL_SRC_FILES := 3rdparty/libopenalpr-static.a
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)

OPENCV_INSTALL_MODULES:=on
OPENCV_CAMERA_MODULES:=off

include d:\Other\robovisor_mobile\OpenCV-android-sdk\sdk\native\jni\OpenCV.mk

LOCAL_MODULE := openalpr-native
SOURCE_LIST := $(wildcard $(LOCAL_PATH)/*.cpp)
HEADER_LIST := $(wildcard $(LOCAL_PATH)/*.h)
LOCAL_SRC_FILES := AlprJNIWrapper.cpp
LOCAL_SRC_FILES += $(HEADER_LIST:$(LOCAL_PATH)/%=%)
LOCAL_SRC_FILES += $(SOURCE_LIST:$(LOCAL_PATH)/%=%)
LOCAL_EXPORT_C_INCLUDES += /home/sujay/builds/src/openalpr/src/openalpr
LOCAL_EXPORT_C_INCLUDES += /home/sujay/builds/src/OpenCV-2.4.9-android-sdk/sdk/native/include
FILE_LIST := $(foreach dir, $(LOCAL_EXPORT_C_INCLUDES), $(wildcard $(dir)/*.cpp))
LOCAL_SRC_FILES := $(FILE_LIST:$(LOCAL_PATH)/%=%)

LOCAL_C_INCLUDES += /home/sujay/builds/src/openalpr/src/openalpr
LOCAL_C_INCLUDES += /home/sujay/builds/src/OpenCV-2.4.9-android-sdk/sdk/native/include
LOCAL_C_INCLUDES += /home/sujay/tools/android-ndk-r10/platforms/android-19/arch-arm/usr/include
LOCAL_SHARED_LIBRARIES += tesseract leptonica
LOCAL_STATIC_LIBRARIES += openalpr support simpleini
LOCAL_LDLIBS := -llog

include $(BUILD_SHARED_LIBRARY)

AlprJNIWrapper.cppにはネイティブ関数が必要です

/**
 * Created by sujay on 13/11/14.
 */
#include <string>
#include <sstream>
#include <cstdio>
#include <iostream>

// openCV includes
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

// open alpr includes
#include "support/filesystem.h"
#include "support/timing.h"
#include "alpr.h"
#include "cjson.h"

#include "AlprJNIWrapper.h"
#include "AlprNative.h"

using namespace alpr;

JNIEXPORT jstring JNICALL Java_org_openalpr_AlprJNIWrapper_recognize(JNIEnv *env,
        jobject object, jstring jimgFilePath, jint jtopN)
{
    jstring defaultCountry = env->NewStringUTF("us");
    jstring defaultRegion = env->NewStringUTF("");
    jstring defaultConfigFilePath = env->NewStringUTF(CONFIG_FILE);
    return _recognize(env, object, defaultCountry, defaultRegion, jimgFilePath, defaultConfigFilePath, jtopN);
}

JNIEXPORT jstring JNICALL Java_org_openalpr_AlprJNIWrapper_recognizeWithCountryNRegion(
        JNIEnv *env, jobject object, jstring jcountry,
        jstring jregion, jstring jimgFilePath, jint jtopN)
{
    jstring defaultConfigFilePath = env->NewStringUTF(CONFIG_FILE);
    return _recognize(env, object, jcountry, jregion, jimgFilePath, defaultConfigFilePath, jtopN);
}

JNIEXPORT jstring JNICALL Java_org_openalpr_AlprJNIWrapper_recognizeWithCountryRegionNConfig
  (JNIEnv *env, jobject object, jstring jcountry, jstring jregion,
          jstring jimgFilePath, jstring jconfigFilePath, jint jtopN)
{
    return _recognize(env, object, jcountry, jregion, jimgFilePath, jconfigFilePath, jtopN);
}

jstring _recognize(JNIEnv *env, jobject object,
        jstring jcountry, jstring jregion, jstring jimgFilePath,
        jstring jconfigFilePath, jint jtopN)
{

    const char* countryChars = env->GetStringUTFChars(jcountry, NULL);

    std::string country(countryChars);

    env->ReleaseStringUTFChars(jcountry, countryChars);

    if(country.empty())
    {
        country = "us";
    }

    const char* configFilePathChars = env->GetStringUTFChars(jconfigFilePath, NULL);

    std::string configFilePath(configFilePathChars);

    env->ReleaseStringUTFChars(jconfigFilePath, configFilePathChars);

    if(configFilePath.empty())
    {
        configFilePath = "/etc/openalpr/openalpr.conf";
    }

    const char* imgFilePath = env->GetStringUTFChars(jimgFilePath, NULL);

    int topN = jtopN;

    std::string response = "";

    cv::Mat frame;
    Alpr alpr(country, configFilePath);

    const char* regionChars = env->GetStringUTFChars(jregion, NULL);

    std::string region(regionChars);

    env->ReleaseStringUTFChars(jregion, regionChars);

    if(region.empty())
    {
        alpr.setDetectRegion(true);
        alpr.setDefaultRegion(region);
    }


    alpr.setTopN(topN);

    if (alpr.isLoaded() == false) {
        env->ReleaseStringUTFChars(jimgFilePath, imgFilePath);
        response = errorJsonString("Error initializing Open Alpr");
        return env->NewStringUTF(response.c_str());
    }

    if(fileExists(imgFilePath))
    {
        frame = cv::imread(imgFilePath);
        response = detectandshow(&alpr, frame, "");
    }
    else
    {
        response = errorJsonString("Image file not found");
    }
    env->ReleaseStringUTFChars(jimgFilePath, imgFilePath);
    return env->NewStringUTF(response.c_str());
}

JNIEXPORT jstring JNICALL Java_org_openalpr_AlprJNIWrapper_version
  (JNIEnv *env, jobject object)
{
    return env->NewStringUTF(Alpr::getVersion().c_str());
}

std::string detectandshow(Alpr* alpr, cv::Mat frame, std::string region) 
{
    std::vector < uchar > buffer;
    std::string resultJson = "";
    cv::imencode(".bmp", frame, buffer);

    std::vector < char > buffer1;

    for(std::vector < uchar >::iterator i = buffer.begin(); i < buffer.end(); i++) {
        buffer1.push_back(*i);
    }

    timespec startTime;
    getTimeMonotonic(&startTime);

    //std::vector < AlprResults > results = alpr->recognize(buffer);
    AlprResults results = alpr->recognize(buffer1);

    timespec endTime;
    getTimeMonotonic(&endTime);
    double totalProcessingTime = diffclock(startTime, endTime);

    //if (results.size() > 0)
    {
        resultJson = alpr->toJson(results/*, totalProcessingTime*/);
    }

    return resultJson;
}

std::string errorJsonString(std::string msg) 
{
    cJSON *root;
    root = cJSON_CreateObject();
    cJSON_AddTrueToObject(root, "error");
    cJSON_AddStringToObject(root, "msg", msg.c_str());

    char *out;
    out = cJSON_PrintUnformatted(root);

    cJSON_Delete(root);

    std::string response(out);

    free(out);
    return response;
}

AlprJNIWrapper.javaはネイティブメソッドを呼び出す

/**
 * 
 */
package org.openalpr;

/**
 * @author sujay
 *
 */
public class AlprJNIWrapper implements Alpr {

        static { 
            System.loadLibrary("lept");
            System.loadLibrary("tess");
            System.loadLibrary("opencv_java");
            System.loadLibrary("openalpr-native");
        }

    /* (non-Javadoc)
     * @see org.openalpr.Alpr#recognize(java.lang.String, int)
     */
    @Override
    public native String recognize(String imgFilePath, int topN);

    /* (non-Javadoc)
     * @see org.openalpr.Alpr#recognizeWithCountryNRegion(java.lang.String, java.lang.String, java.lang.String, int)
     */
    @Override
    public native String recognizeWithCountryNRegion(String country, String region,
            String imgFilePath, int topN);

    /* (non-Javadoc)
     * @see org.openalpr.Alpr#recognizeWithCountryRegionNConfig(java.lang.String, java.lang.String, java.lang.String, java.lang.String, int)
     */
    @Override
    public native String recognizeWithCountryRegionNConfig(String country,
            String region, String imgFilePath, String configFilePath, int topN);

    /*
     * (non-Javadoc)
     * @see org.openalpr.Alpr#version()
     */
    @Override
    public native String version();
}

編集済み

私の携帯電話にはプロセッサに関する情報があります。

Processor       : ARMv7 Processor rev 3 (v7l)
processor       : 0
BogoMIPS        : 1993.93

Features        : swp half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpv4
idiva idivt
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xc07
CPU revision    : 3

再度編集

結果ファイル内の関数に関する情報を取得しようとしました.soが、次のような結果が返されました:

Symbol table '.dynsym' contains 6 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 FUNC    GLOBAL DEFAULT  UND __cxa_finalize
     2: 00000000     0 FUNC    GLOBAL DEFAULT  UND __cxa_atexit
     3: 00002004     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
     4: 00002004     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
     5: 00002004     0 NOTYPE  GLOBAL DEFAULT  ABS _end

以下から入手しました:

<ndk_path>\toolchains\arm-linux-androideabi-4.8\prebuilt\windows\bin>arm-linux-androideabi-readelf.exe 
-Ws <projects_path>\libs\armeabi-v7a\libopenalpr-native.so

.so何か間違ったことをしているのでしょうか? それとも、ファイルに関数が本当に存在しないのでしょうか?

ベストアンサー1

いくつかの問題が考えられます。
まず、サポートされていないデバイスでサンプルを実行します。たとえば、ライブラリが armeabi-v7 用にビルドされていて ( APP_ABI := armeabi-v7amake ファイルの設定により確実にそうなる)、デバイスが intel x86 または armeabi バージョン 7 未満である場合などです。
ライブラリ プロジェクトが更新されているのにサンプルが古くなっている可能性があり、そのため一部のメソッド名が変更されたり、メソッドが非推奨として削除されたりします。
また、コンパイルされた NDK ライブラリはパッケージに依存するため、JNI クラスを別のパッケージに配置すると動作しません。
また、ネイティブ ライブラリの .so ファイルは、プロジェクトの適切な場所に配置する必要があり、通常 jar-libs を配置する libs フォルダーではありません。これは、Android Studio の場合とは少し異なるフォルダーです。

...\src\main\jniLibs\aremabi-v7a\libYourLib.so (aremabi-v7a バージョンの場合)
...\src\main\jniLibs\x86\libYourLib.so (x86 バージョンなどの場合)

アップデート:
最小APIレベル19を尊重することを忘れないでください。アプリはそれより低いAPIレベルのデバイスでは動作しません。つまり、プロジェクトで最小APIレベルを変更することもできますが、変更しないでください。
ここでの問題は、名前にlibopenalpr-native.soダッシュ-文字が含まれていることです。ダッシュはAOSのリソース命名で制限されている文字です。そのため、これを「_」に置き換えてアプリは動作するようになりましたここでも置き換えます:

System.loadLibrary("openalpr_native");

そして、私はあなたの .so のバージョンを使用せず、プロジェクトに含まれているものだけを使用しました。
アップデート
見てみましょう:http://prntscr.com/6w6qfxあなたのライブラリは、元の 1.7 MB と比較してわずか 5 KB です。間違いなく何かが間違っています。コメントであなたの質問について説明しています:

System.loadLibrary("openalpr-native"); にエラーがないのはなぜですか? この状況が理解できません。libopenalpr-native.so ファイルを作成し、プログラムにロードしますが、メソッドがありません。

代わりにサンプル プロジェクトに含まれている元のライブラリを使用できますか? テストのためだけです。

おすすめ記事