手机APP开发之车牌识别SDK移植

明:本文所提到的代码以及库(动态链接库so或者静态库lib)可能来源于第三方成熟产品。

作者仅保留自己所研究部分内容的所有权。

本文中所提到相关工具,仅供学习参考使用,不得作为商业用途。

1、需求

使用手机(暂限于ANDROID平台手机)相机捕获车牌图像,能够识别车牌号码。识别率达到90%以上。

细化需求:

(1)支持多Android版本(API Level 8~2x),Android 1.5 ~ 4.4.x

(2)要求相机自动聚焦,以保证获取图像质量

(3)图像识别时间不大于6s

(4)图像识别率>90%

手机APP开发之车牌识别SDK移植_第1张图片

2、思路

(1)市场分析,体验现有车牌识别产品,进行研究,拟进行整合

(2)相关方案按照难度的易→程度,排列如下:

    a:基于界面调用,获取返回结果(Activity调用,前提需要安装依赖APP)

    b:基于代码反编译,基于接口重用(网络通信接口调用,依赖于对方的调用政策)

    c:基于代码反编译,基于动态库重用(JNI应用)

    d:基于代码反编译,代码重用(依赖于代码反编译难度,例如:工程有否混淆、反编译工具的选择)

    e:基于代码反编译,代码的理解,重构

3、研究过程

    (1)目标:现有车牌识别APP产品:文通、云脉

    (2)工具:反编译工具:dex2jar v2.0、jad 1.5.8g 和AXMLPrinter2.jar (截止2015.6.25日的最新版本)

    (3)步骤

        a:下载apk文件,并解压

        b:使用dex2jar工具,输入classes.dex文件生成classes-dex2jar.jar

        c:使用jad工具,输入classes-dex2jar.jar中的class文件生成java源文件

        d:使用AXMLPrinter2.jar,输入AndroidManifest.xml生成AndroidManifest.xml.txt

        e:开始进行代码分析

4、研究结果

    (1)无论文通还是云脉的手机app,前者为V1.2.3,后者为V3.0,都使用JNI方式进行API的调用

    (2)适用于上述方案C的方式,即基于代码反编译,基于动态链接库重用

    (3)云脉使用的动态链接库文件:libimageengine.so、libpnocrengine.so,
          对应的接口声明在hotcard.doc.reader.NativeImage和NativeOcrPn中定义

    (4)文通使用的动态链接库文件:libTHPlateIDFree.so、libCWImage.so,

          对应的接口声明在com.wintone.plateid.PlateIDAPI中定义

    (5)相比之下,文通产品的经验和技术底蕴较为深厚,将以文通产品进行研究


PlateIDAPI的定义:

<span style="font-size:12px;">package com.wintone.plateid;

import com.wintone.plate.Package;

/**
 * 车牌识别API
 * @author PAUL 
 * @mail [email protected]
 * @date 2015-06-01
 */
public class PlateIDAPI
{

    public PlateIDAPI()
    {
    }

	//返回车牌识别库版本。 格式: 主版本号 .副版本号  .修订号 .编译号  。
    public static native String TH_GetVersion();

	  /**
	   * 初始化识别库
	   * @param paramTH_PlateIDCfg
	   * @param paramPackage 车牌识别SDK的配置
	   * @return
	   */
    public static native int TH_InitPlateIDSDK(
		TH_PlateIDCfg th_plateidcfg, 
		Package package1);

    public static native int TH_InitPlateIDSDKTF(
		TH_PlateIDCfg th_plateidcfg);

	//识别图片
    public static native TH_PlateIDResult[] TH_RecogImage(
		String s, 
		int i, 
		int j, 
		TH_PlateIDResult th_plateidresult, 
		int ai[], 
		int k, 
		int l, 
		int i1,
		int j1, 
		int ai1[]);

	//识别图像
    public static native TH_PlateIDResult[] TH_RecogImageByte(
		byte abyte0[], 
		int i, 
		int j, 
		TH_PlateIDResult th_plateidresult, 
		int ai[], 
		int k, 
		int l, 
		int i1, 
		int j1, 
		int ai1[]);

    public static native int TH_SetAutoSlopeRectifyMode(
		int i, 
		int j);

    public static native int TH_SetContrast(
		int i);

	//设置夜间模式
    public static native int TH_SetDayNightMode(
		int i);

	//设置对特殊车牌的识别
    public static native int TH_SetEnabledPlateFormat(
		int i);

    public static native int TH_SetEnlargeMode(
		int i);

	//设置图像格式
    public static native int TH_SetImageFormat(
		int i, 
		int j, 
		int k);

	//设置默认省份
    public static native int TH_SetProvinceOrder(
		String s);

	//设置识别阈值
    public static native int TH_SetRecogThreshold(
		int i, 
		int j);

    public static native int TH_UninitPlateIDSDK();

    static 
    {
        System.loadLibrary("CWImage");
        System.loadLibrary("THPlateIDFree");
    }
};</span>
接口调用规则推测

    (1)TH_InitPlateIDSDK

    (2)TH_Setxxxxx

    (3)TH_RecogImage 或 TH_RecogImageByte

    (4)TH_UninitPlateIDSDK

5、试验

    (1)初始化SDK;

    (2)调用系统相机进行拍照(1280x960像素的分辨率);

    (3)调用识别函数进行车牌图片的识别;关键代码如下;

    (4)返回调用结果,如果成功,则返回所识别的车牌颜色和号码。

	/**
	 * 识别车牌图片文件
	 * @param filePath2 文件路径
	 * @return 车牌颜色+车牌号码
	 */
	private String recognizeImageFile(String filePath2) {

		//Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
		TH_PlateIDResult localResult = new TH_PlateIDResult();
		int[] array1 = new int[1];
		array1[0] = 10;
		int[] array2 = new int[1];
		array2[0] = -1;
		
		File file = new File(filePath);
		if(!file.exists()) {
			Logger.getLogger(IDef.App_Tag).log(Level.WARNING, "Read image ["+filePath+"] failure");
			return (null);
		}
		
		PlateIDAPI.TH_SetImageFormat(1, 0, 1);
		ConfigArgument configArg = new ConfigArgument();
		
        PlateIDAPI.TH_SetEnabledPlateFormat(configArg.individual);
        PlateIDAPI.TH_SetEnabledPlateFormat(configArg.tworowyellow);
        PlateIDAPI.TH_SetEnabledPlateFormat(configArg.armpolice);
        PlateIDAPI.TH_SetEnabledPlateFormat(configArg.tworowarmy);
        PlateIDAPI.TH_SetEnabledPlateFormat(configArg.tractor);
        PlateIDAPI.TH_SetEnabledPlateFormat(configArg.onlytworowyellow);
        PlateIDAPI.TH_SetEnabledPlateFormat(configArg.embassy);
        PlateIDAPI.TH_SetEnabledPlateFormat(configArg.onlylocation);
        PlateIDAPI.TH_SetEnabledPlateFormat(configArg.armpolice2);
        PlateIDAPI.TH_SetRecogThreshold(7, 5);
        PlateIDAPI.TH_SetContrast(9);	
		
		TH_PlateIDResult[] result = PlateIDAPI.TH_RecogImage(file.getAbsolutePath(), 
				CaptureActivity.Desired_Picture_Width, CaptureActivity.Desired_Picture_Height, localResult,
				array1, 0, 0, 0, 0,array2);
		
		if( (result == null) || (result.length== 0) ) { //识别失败
			Logger.getLogger(IDef.App_Tag).log(Level.WARNING, "Image recognize failure");
			file.delete();
			return (null);
		}
		
		StringBuffer sb = new StringBuffer();
		sb.append(result[0].toString() );
		
		//更名
		File newFile = new File(IDef.App_Dir+File.separatorChar+result[0].getLicense()+".jpg");
		file.renameTo(newFile);
		file.delete();
		
		return (sb.toString() );
	}

6、结语

    可能由于考虑到网络传输流量的因素,所有车牌(包括证件)识别的APP都采用了本地解析的策略;而采用的本地解析策略都使用了JNI的方式进行包装,即:核心代码端都采用C或C++编写的链接库,本地使用JNI方式进行调用。所以,基于动态库重用(JNI应用)的方案应该是比较可行的。实验证明,通过重用清华紫光的车牌识别的链接库,可以实现较好的车牌识别效果。【完结】


相关下载

(1)说明文档:http://download.csdn.net/detail/paulorwys/8836519

(2)链接库:http://download.csdn.net/detail/paulorwys/8839447

你可能感兴趣的:(jni,反编译,android平台,车牌识别)