Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android ocr——身份證識別的功能實現

android ocr——身份證識別的功能實現

編輯:關於Android編程

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 下載地址:https://github.com/justin/tesseract-ocr

今天我不講如何編譯 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:[email protected] 
 * 這個類 就是調用 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問題

然後我們需要把識別集成到二維碼掃描裡面 

下面這個對二維碼掃描這個項目介紹的比較詳細

http://www.jb51.net/article/53487.htm

下面給大家介紹一下,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

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved