概述
本文介绍如何在android平台上进行车牌的检测与识别。检测是利用easyPR做的,主要用到SVM这个机器学习算法,识别是用深度学习做的,用caffe训练字符的识别模型,然后跑在android平台上。先说下具体思路,先编译easyPR与caffe的动态库,然后在android上使用easyPR动态库进行车牌的检测与切割,调用caffe的动态库,对切割后的字符图片进行依次识别。最终效果图(暂时不支持汉字的识别)
步骤
easyPR车牌检测动态库编译
- 搭建android开发平台,android+sdk(密码:6jf7)+ndk,要保证javah能使用
- 新建PlateDetect,新建类PlateDetectMobile.java,类中定义native的方法,具体代码用c++实现,编译成动态库后在java中调用。
public class PlateDetectMobile {
/*picturePath指定车牌的存储路径,resultSavePath指定检测结果的存储路径,svmPath指定SVM.xml的存储路径*/
public native void nativePlateDetect(String picturePath,
String resultSavePath,String svmPath);
}
- 点击Build->Make Project,生成类的PlateDetectMobile.class文件
- 打开控制台,进入PlateDetectMobile.classs所在文件夹
cd E:\PlateDetect\app\build\intermediates\classes\debug
- 生成.h文件
javah -classpath . -jni com.example.hwt.myapplication.PlateDetectMobile
- 在debug文件夹下找到生成的com_example_hwt_platedetect_PlateDetectMobile.h文件,在项目中新建文件夹jni,将.h文件拷贝到jni下。.h文件主要定义了需要实现的方法
JNIEXPORT void JNICALL Java_com_example_hwt_platedetect_PlateDetectMobile_nativePlateDetect
(JNIEnv *, jobject, jstring, jstring,jstring);
- 在jni下新建PlateDetect.cpp文件,实现.h文件中定义的方法
#include <com_example_hwt_platedetect_PlateDetectMobile.h>
JNIEXPORT void JNICALL Java_com_example_hwt_platedetect_PlateDetectMobile_nativePlateDetect
(JNIEnv *env, jobject, jstring picturePath, jstring resultSavaPath,jstring svmPath){
/*
将3个jstring参数转化为string参数,然后就可以全程用C++了
将需要用到的.h文件和.cpp文件拷贝到jni文件夹中,.cpp文件需要在android.mk(可以理解为Makefile)中声明
opencv的使用在android.mk中指定库文件目录,不要将代码拷贝到jni中
*/
}
- 下载OpenCV-2.4.11-android-sdk
- 新建Android.mk文件
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#需要用到相机则设置为on
OPENCV_CAMERA_MODULES:= off
OPENCV_INSTALL_MODULES:=on
OPENCV_LIB_TYPE:=STATIC
#指定opencv库文件目录
include E:\OpenCV-2.4.11-android-sdk\OpenCV-android-sdk\sdk\native\jni\OpenCV.mk
#jni中用到的cpp文件都要在此声明
LOCAL_SRC_FILES := PlateDetect.cpp \
plate_detect.cpp \
core_func.cpp \
feature.cpp\
plate.cpp\
plate_judge.cpp\
plate_locate.cpp \
chars_segment.cpp
LOCAL_C_INCLUDES += $(LOCAL_PATH)
LOCAL_LDLIBS += -llog -ldl \
-latomic
//编译后动态库的名称
LOCAL_MODULE := PlateDetectmobile
include $(BUILD_SHARED_LIBRARY)
- 在Jni中新建Application.mk
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
#编译出可以在以下平台中运行的动态库
APP_ABI := armeabi armeabi-v7a x86
APP_PLATFORM := android-9
- 打开控制台,进入jni所在目录,执行ndk-build
cd E:\PlateDetect\app\src\main\jni
ndk-build
- 修改build.grade(Module:app)
import org.apache.tools.ant.taskdefs.condition.Os
apply plugin: 'com.android.application'
android {
//编译的sdk版本,需要为21及以上,因为以下的版本无法使用后面编译的caffe动态库
compileSdkVersion 22
buildToolsVersion "25.0.0"
defaultConfig {
applicationId "com.example.hwt.platedetect"
minSdkVersion 18
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets { main { res.srcDirs = ['src/main/res', 'src/main/res/raw'] } }
//执行ndk-build之后会生成libs文件夹,设置jniLibs文件夹为libs文件夹中的文件
sourceSets.main {
jniLibs.srcDir 'src/main/libs'
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:22.2.1'
}
//隐藏jni文件夹,不然会报错
android {
sourceSets {
main {
jni.srcDirs = []
}
}
}
android {
sourceSets {
main { java.srcDirs = ['src/main/java','src/main/java/com/sh1r0/caffe/android/lib;'] }
}
}
- dd
- 修改build.gradle后,点击Sync Now,会看到jni文件夹被隐藏了,出现了jniLibs文件夹,该文件夹下就是我们编译出来的动态库
caffe android平台移植
- caffe的android平台移植已经有人给我们做好了,在GitHub上可以找到这个开源框架caffe-android-lib,我们需要利用这个开源框架编译出caffe的动态库。以下操作都是在CentOS 7.3下进行的,当前目录为/home/hwt
- 下载ndk并解压
wget https://dl.google.com/android/repository/android-ndk-r13b-linux-x86_64.zip
unzip android-ndk-r13b-linux-x86_64.zip
- 编译caffe动态库
#下载caffe-android-lib
git clone --recursive https://github.com/sh1r0/caffe-android-lib.git
#进入文件夹
cd caffe-android-lib
#设置要运行该动态的处理器
export ANDROID_ABI="arm64-v8a"
#执行脚本,编译动态库 后面的参数为ndk路径
./build.sh /home/hwt/android-ndk-r13