2015-04-08 14 views
42

Per alcuni giorni sto cercando di creare OpenALPR example project for Android. Costruisce e lanci, ma dopo aver chiamato il metodo nativo per riconoscerlo fa eccezione:Unsatisfiedlinkerror Progetto di prova OpenALPR per Android

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 

io non posso fare nulla, sembra tutto il tempo.

Application.mk

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

Android.mk dopo tutti i miei tentativi

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 contiene necessario per me funzioni native

/** 
* 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 chiamate native metodo

/** 
* 
*/ 
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(); 
} 

cura

C'è informazioni su processore sul mio cellulare.

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 

A cura di nuovo

ho cercato di ottenere informazioni sulla funzione del risultato .so di file e non v'è ciò che ottengo:

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 

ricevo da:

<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 

Sto facendo qualcosa di sbagliato? O non ci sono davvero le mie funzioni nel file .so?

+0

potrebbe essere che un campione non è aggiornato. Sebbene gli sviluppatori avessero aggiornato la lib di NDK, non hanno apportato le seguenti modifiche nel progetto di esempio. O non c'è solo la versione lib per il tuo ARM. – Stan

+0

Non c'è lib, ma build del progetto? Spero di no. – Ircover

+0

Esiste ovviamente una soluzione. Ma nessuna versione per il tuo braccio. In questo modo il progetto verrà compilato senza alcun problema. Tuttavia non funzionerà sul tuo dispositivo particolare. Diciamo che il tuo dispositivo è basato su MIPS e che il progetto ha solo arm-v7. O il tuo deice è Intel x86. – Stan

risposta

9

Ci possono essere diversi problemi.
Innanzitutto, si esegue l'esempio su dispositivo non supportato, ad esempio se lib è stato creato per armeabi-v7 (ed è sicuramente dovuto all'impostazione APP_ABI := armeabi-v7a nel file make) e il dispositivo è intel x86 o inferiore a 7 versione armeabi, ecc.
Potrebbe essere che il campione non sia aggiornato mentre il progetto lib è stato aggiornato, quindi alcuni nomi di metodo sono stati modificati o il metodo è stato rimosso come deprecato, ecc.
Anche la lib di NDK compilata è sensibile al pacchetto, quindi se si posiziona la classe JNI in un pacchetto diverso non funzionerà o.
Anche la libreria nativa .so-file deve essere collocata nel posto giusto del progetto e non è una cartella di libs in cui si collocano normalmente jar-libs. La sua cartella diversa un po 'come per quanto riguarda Android Studio:

...\src\main\jniLibs\aremabi-v7a\libYourLib.so (for aremabi-v7a version)
...\src\main\jniLibs\x86\libYourLib.so (for x86 version and so on)

UPDATE:
Non dimenticare di rispettare il livello di API min che è 19. App non funzionerà su dispositivi con livello di API inferiore, voglio dire è possibile modificare il livello API minimo nel progetto, non farlo.
Il problema qui è che libopenalpr-native.so ha un trattino - caratteri nel suo nome. Dash è un carattere limitato per la denominazione delle risorse in AOS.Così ho sostituito con "_" e app works now e sostituirlo anche qui:

System.loadLibrary("openalpr_native"); 

E non ho usato la versione di .so, ma solo l'incluso in un unico progetto.
UPDATE
Date un'occhiata: http://prntscr.com/6w6qfx la vostra lib è a soli 5kb rispetto al 1.7Mb originale c'è qualcosa di sbagliato sicuramente. E spiega la tua domanda nel commento:

Why there is no error on System.loadLibrary("openalpr-native");? I just can't understand this situation - creates libopenalpr-native.so file, it loads to program, by there is no method.

Potresti semplicemente utilizzare la lib originale inclusa nel progetto di esempio? Solo per testare

+0

Quindi perché non è aumentato l'errore durante la compilazione? Perché non ci sono errori su 'System.loadLibrary (" openalpr-native ");'? Non riesco proprio a capire questa situazione - crea il file 'libopenalpr-native.so', che carica per programmare, non esiste un metodo. – Ircover

+0

Tentativo di ottenere la libreria per un altro processore - 'java.lang.UnsatisfiedLinkError: Impossibile caricare il lept dal loader dalvik.system.PathClassLoader [DexPathList [[zip file" /data/app/com.example.robovisormobile-1.apk " ], nativeLibraryDirectories = [/ data/app-lib/com.example.robovisormobile-1,/vendor/lib,/system/lib]]]: findLibrary ha restituito null' – Ircover

+0

Sei sicuro di non aver cambiato il nome del pacchetto? – Stan

3

Nessun metodo corretto trovato nella libreria è dovuto alla mancata corrispondenza del nome, è necessario includere il codice della funzione JNI con extern "C" in codice C++.