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.