tutorial source software recognition plate openalpr open number automatic java android c++ android-ndk

java - source - Proyecto de prueba OpenALPR Insatisfactorio para Android



openalpr tutorial (2)

Ningún método correcto encontrado en su biblioteca se debe a la falta de coincidencia de nombres, debe envolver su código de función JNI con una extern "C" en el código C ++.

Por unos días estoy tratando de construir el proyecto de ejemplo OpenALPR para Android . Se construye y se inicia, pero después de llamar al método nativo para reconocerlo, se hace una excepción:

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

No puedo hacer nada, aparece todo el tiempo.

Aplicación.mk

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

Android.mk después de todos mis intentos

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 las funciones nativas necesarias para mí

/** * 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 llama método nativo

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

Editado

Hay información sobre el procesador en mi teléfono.

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

Editado de nuevo

Intenté obtener información sobre la función en el archivo result .so y obtengo lo siguiente:

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

Lo obtengo de:

<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

¿Estoy haciendo algo mal? O realmente no hay mis funciones en el archivo .so ?


Puede haber varios problemas.
Primero, ejecute la muestra en un dispositivo no compatible, como si lib se hubiera creado para armeabi-v7 (y definitivamente se debe a APP_ABI := armeabi-v7a en el archivo make) y su dispositivo es intel x86 o inferior a 7 versiones de armeabi, etc. .
Podría ser que la muestra esté desactualizada mientras que el proyecto lib se haya actualizado, por lo que se cambiaron algunos nombres de métodos o se eliminó el método como obsoleto, etc.
También la compilación NDK compilada es sensible al paquete, por lo que si coloca la clase JNI en un paquete diferente, tampoco funcionará.
Además, el archivo .so de la biblioteca nativa debe colocarse en el lugar correcto de su proyecto y no es una carpeta libs donde se colocan normalmente jar-libs. Es una carpeta un poco diferente como para Android Studio:

... / src / main / jniLibs / aremabi-v7a / libYourLib.so (para la versión aremabi-v7a)
... / src / main / jniLibs / x86 / libYourLib.so (para la versión x86 y así sucesivamente)

ACTUALIZAR:
No se olvide de respetar el nivel mínimo de API, que es el 19. La aplicación no funciona en dispositivos con un nivel de API más bajo, quiero decir que podría cambiar el nivel mínimo de API en el proyecto, no lo haga.
El problema aquí es que libopenalpr-native.so tiene un dash - char en su nombre. Dash es un char restringido para nombrar recursos en AOS. Así que lo reemplacé con "_" y la aplicación ahora funciona. Y también la reemplacé aquí:

System.loadLibrary("openalpr_native");

Y no usé su versión de .so, sino solo la incluida en el proyecto uno.
ACTUALIZAR
Eche un vistazo: http://prntscr.com/6w6qfx su lib es de solo 5kb en comparación con los 1.7Mb originales, definitivamente hay algo mal. Y explica tu pregunta en el comentario:

¿Por qué no hay ningún error en System.loadLibrary ("openalpr-native") ;? Simplemente no puedo entender esta situación: crea el archivo libopenalpr-native.so, se carga en el programa, ya que no hay ningún método.

¿Podría simplemente usar lib original incluido en el proyecto de ejemplo en su lugar? Sólo para probar.