欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

android ocr——身份证识别的功能实现

程序员文章站 2024-02-29 15:35:04
ocr opencv 想必做过程图像识别的同学们都对这两个词不陌生吧。 ocr (optical character recognition ,光学字符识别) 是指电子设...

ocr opencv 想必做过程图像识别的同学们都对这两个词不陌生吧。

ocr (optical character recognition ,光学字符识别) 是指电子设备(例如扫描仪或数码相机)检查纸上的字符,通过检测暗,亮的模式确定其形状,然后用字符识别方法将形状翻译成计算机文字的过程。 这样就给我编程提供了接口,我们可以识别图片的文字了 (有些文档我们通过手机拍照的,直接生成word )身份证识别,银行卡识别等。

opencv 是什么呢

opencv的全称是:open source computer vision library。opencv是一个基于bsd许可(开源)发行的跨平台计算机视觉库,可以运行在linux、windows和mac os操作系统上。它轻量级而且高效——由一系列 c 函数和少量 c++ 类构成,同时提供了python、ruby、matlab等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。

上面是 百度百科给出的定义说白了就是给我们编程提供的类库而已

android 如果想使用ocr 

我们可以使用google 开源的项目tesseract-ocr

github 下载地址:

今天我不讲如何编译 ocr 这个东西 

主要说下,识别二维码的这个项目和tesseract-ocr 整合成一个识别身份证号码的 过程

后面我会把他们编译成类库供大家使用的

orc 识别方法已经封装成一个简单的类 ocr

package com.dynamsoft.tessocr; 
 
import android.content.context; 
import android.content.res.assetmanager; 
import android.graphics.bitmap; 
import android.os.environment; 
 
import com.googlecode.tesseract.android.tessbaseapi; 
 
import java.io.file; 
 
/** 
 * created by cyl on 2016/3/26. 
 * email:670654904@qq.com 
 * 这个类 就是调用 ocr 的接口 
 * 这个是识别过程是耗时的 操作 请放到线程 操作 
 */ 
public class ocr { 
  private tessbaseapi mtess; 
  private boolean flag; 
  private context context; 
  private assetmanager assetmanager; 
 
  public ocr() { 
    // todo auto-generated constructor stub 
 
    mtess = new tessbaseapi(); 
    string datapath = environment.getexternalstoragedirectory() + "/tesseract/"; 
    string language = "eng"; 
    //请将你的语言包放到这里 sd 的 tessseract 下的tessdata 下 
    file dir = new file(datapath + "tessdata/"); 
    if (!dir.exists()) 
      dir.mkdirs(); 
    flag = mtess.init(datapath, language); 
  } 
 
  /** 
   * 识别出来bitmap 上的文字 
   * @param bitmap 需要识别的图片 
   * @return 
   */ 
  public string getocrresult(bitmap bitmap) { 
    string result = "dismiss langues"; 
    if(flag){ 
      mtess.setimage(bitmap); 
      result = mtess.getutf8text(); 
    } 
 
    return result; 
  } 
 
  public void ondestroy() { 
    if (mtess != null) 
      mtess.end(); 
  } 
} 

方法很简单 :

创建对象,调用getocrresult方法就行了,注意这个识别过程是耗时,放到线程去操作。避免anr问题

然后我们需要把识别集成到二维码扫描里面 

下面这个对二维码扫描这个项目介绍的比较详细

下面给大家介绍一下,zxing库里面主要的类以及这些类的作用:

  • captureactivity。这个是启动activity 也就是扫描器。
  • captureactivityhandler 解码处理类,负责调用另外的线程进行解码。
  • decodethread 解码的线程。
  • com.google.zxing.client.android.camera 包,摄像头控制包。
  • viewfinderview 自定义的view,就是我们看见的拍摄时中间的框框了。

 我可以简单考虑一下  图片识别,我们需要先获取图片才能识别,当识别成功以后应该将数据返回  并反馈给用户我们已经完成了识别。

第一首先 我们如何获取图像 即 bitmap 从上面主要功能的类可以看出来。

我应该去captureactivityhandler 解码处理处理中去找,不管识别二维码还是图片,身份证啊。最终都是识别bitmap

所以我们这里可以找到相机捕捉到的图像;

decodehandler

 /* 
 * copyright (c) 2010 zxing authors 
 * 
 * licensed under the apache license, version 2.0 (the "license"); 
 * you may not use this file except in compliance with the license. 
 * you may obtain a copy of the license at 
 * 
 *   http://www.apache.org/licenses/license-2.0 
 * 
 * unless required by applicable law or agreed to in writing, software 
 * distributed under the license is distributed on an "as is" basis, 
 * without warranties or conditions of any kind, either express or implied. 
 * see the license for the specific language governing permissions and 
 * limitations under the license. 
 */ 
 
package com.sj.app.decoding; 
 
import android.graphics.bitmap; 
import android.os.bundle; 
import android.os.handler; 
import android.os.looper; 
import android.os.message; 
import android.util.log; 
 
import com.dynamsoft.tessocr.ocr; 
import com.google.zxing.binarybitmap; 
import com.google.zxing.decodehinttype; 
import com.google.zxing.multiformatreader; 
import com.google.zxing.readerexception; 
import com.google.zxing.result; 
import com.google.zxing.common.hybridbinarizer; 
import com.sj.app.camera.cameramanager; 
import com.sj.app.camera.planaryuvluminancesource; 
import com.sj.app.utils.idmatch; 
import com.sj.erweima.mipcaactivitycapture; 
import com.sj.erweima.r; 
 
import java.util.hashtable; 
import java.util.list; 
 
final class decodehandler extends handler { 
 
  private static final string tag = decodehandler.class.getsimplename(); 
 
  private final mipcaactivitycapture activity; 
  private final multiformatreader multiformatreader; 
 
  decodehandler(mipcaactivitycapture activity, 
         hashtable<decodehinttype, object> hints) { 
    multiformatreader = new multiformatreader(); 
    multiformatreader.sethints(hints); 
    this.activity = activity; 
  } 
 
  @override 
  public void handlemessage(message message) { 
    switch (message.what) { 
      case r.id.decode: 
        // log.d(tag, "got decode message"); 
        decode((byte[]) message.obj, message.arg1, message.arg2); 
        break; 
      case r.id.quit: 
        looper.mylooper().quit(); 
        break; 
    } 
  } 
 
  /** 
   * decode the data within the viewfinder rectangle, and time how long it 
   * took. for efficiency, reuse the same reader objects from one decode to 
   * the next. 
   * 
   * @param data 
   *      the yuv preview frame. 
   * @param width 
   *      the width of the preview frame. 
   * @param height 
   *      the height of the preview frame. 
   */ 
  private void decode(byte[] data, int width, int height) { 
    long start = system.currenttimemillis(); 
    result rawresult = null; 
 
    // modify here 
    byte[] rotateddata = new byte[data.length]; 
    for (int y = 0; y < height; y++) { 
      for (int x = 0; x < width; x++) 
        rotateddata[x * height + height - y - 1] = data[x + y * width]; 
    } 
    int tmp = width; // here we are swapping, that's the difference to #11 
    width = height; 
    height = tmp; 
 
    planaryuvluminancesource source = cameramanager.get() 
        .buildluminancesource(rotateddata, width, height); 
    binarybitmap bitmap = new binarybitmap(new hybridbinarizer(source)); 
    try { 
      //相机中捕捉到的 
      bitmap image = source.rendercroppedgreyscalebitmap(); 
      doorc(source); 
      rawresult = multiformatreader.decodewithstate(bitmap); 
    } catch (readerexception re) { 
      // continue 
    } finally { 
      multiformatreader.reset(); 
    } 
 
    if (rawresult != null) { 
      long end = system.currenttimemillis(); 
      log.d(tag, "found barcode (" + (end - start) + " ms):\n" 
          + rawresult.tostring()); 
      message message = message.obtain(activity.gethandler(), 
          r.id.decode_succeeded, rawresult); 
      bundle bundle = new bundle(); 
      bundle.putparcelable(decodethread.barcode_bitmap, 
          source.rendercroppedgreyscalebitmap()); 
      message.setdata(bundle); 
      // log.d(tag, "sending decode succeeded message..."); 
      message.sendtotarget(); 
    } else { 
      message message = message.obtain(activity.gethandler(), 
          r.id.decode_failed); 
      message.sendtotarget(); 
    } 
  } 
  private handler handler = new handler(){ 
    public void handlemessage(message msg) { 
      cardid cardid = (cardid) msg.obj; 
      if(cardid != null){ 
        message message = message.obtain(activity.gethandler(), 
            r.id.decode_succeeded, cardid.id); 
        bundle bundle = new bundle(); 
        bundle.putparcelable(decodethread.barcode_bitmap, 
            cardid.bitmap); 
        message.setdata(bundle); 
        // log.d(tag, "sending decode succeeded message..."); 
        message.sendtotarget(); 
      } 
    }; 
  }; 
  private void doorc(final planaryuvluminancesource source) { 
    new thread(new runnable() { 
      @override 
      public void run() { 
        bitmap bitmap = source.rendercroppedgreyscalebitmap(); 
        string id = new ocr().getocrresult(bitmap); 
        if(id != null){ 
          list<string> list = idmatch.machid(id); 
          if(list!= null && list.size()>0){ 
            string cardid = list.get(0); 
            if(cardid != null){ 
              message msg = message.obtain(); 
              cardid cardid2 = new cardid(cardid, bitmap); 
              msg.obj = cardid2; 
              handler.sendmessage(msg); 
            } 
          } 
        } 
 
      } 
    }).start(); 
  } 
  public class cardid{ 
    private string id; 
    private bitmap bitmap; 
    public cardid(string id, bitmap bitmap) { 
      super(); 
      this.id = id; 
      this.bitmap = bitmap; 
    } 
    public string getid() { 
      return id; 
    } 
    public void setid(string id) { 
      this.id = id; 
    } 
    public bitmap getbitmap() { 
      return bitmap; 
    } 
    public void setbitmap(bitmap bitmap) { 
      this.bitmap = bitmap; 
    } 
 
  } 
 
} 

当解析成功的时候就将结果通过handler 返回到ui 线程中去了,对于 扫描框我们可以响应调节。

cameramanager 这个类 控制扫描框的大小。

public rect getframingrect() { 
  point screenresolution = configmanager.getscreenresolution(); 
  if (framingrect == null) { 
   if (camera == null) { 
    return null; 
   } 
   int width = screenresolution.x * 7 / 8; 
   if (width < min_frame_width) { 
    width = min_frame_width; 
   } else if (width > max_frame_width) { 
//    width = max_frame_width; 
   } 
   int height = screenresolution.y * 3 / 4; 
   if (height < min_frame_height) { 
    height = min_frame_height; 
   } else if (height > max_frame_height) { 
    height = max_frame_height; 
   } 
   int leftoffset = (screenresolution.x - width) / 2; 
   int topoffset = (screenresolution.y - height) / 2; 
   framingrect = new rect(leftoffset, topoffset, leftoffset + width, topoffset + height); 
   log.d(tag, "calculated framing rect: " + framingrect); 
  } 
  return framingrect; 
 } 

改变这个方法就可以改变这个扫描框的大小了。

需要提示的是 如果您的手机是android 6.0以上 请查看 sd卡根目录是否存在tesseract/tessdata目录 以及下面的文件  如果没有存在说明 应用没有获取到存储权限。

原文链接:http://blog.csdn.net/tiandiyinghun/article/details/50985961

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。