Accura OCR

High Accuracy OCR (Optical Character Recognition) Includes English, Latin, Chinese, Korean and Japanese Languages.

Step 1: Before you begin

  1. If you haven't done already then follow Project Setup steps.

  2. Please download the Accura Scan license and then add it to your app.

  3. Download license from here

  4. Move your key.license file into the module (app-level) assets folder (usually <project>/<app-module>/src/main/assets)

Note: Make sure license file name should be key.license

  1. Permissions required

    1. Camera Permission android.permission.CAMERA

    2. Storage Permission required only for print out debug logs.

Note: Enable logging for debugging purposes using the methods provided below. Please remember to disable logging before releasing the app. (Storage permission is required for logging). AccuraLog.enableLogs(true); AccuraLog.refreshLogfile(activity); Log file will be stored in InternalStorage/Downloads/AccuraLog.txt

Step 2: Initialize SDK when the app starts

  1. Initialize SDK with Licensing

    RecogEngine recogEngine = new RecogEngine();
    RecogEngine.SDKModel sdkModel = recogEngine.initEngine(your activity context);
    
    // Error Message if license is not valid.
    String licenseErrorMessage = sdkModel.message;
    
    if (sdkModel.i > 0) { // if license is valid
    
         if (sdkModel.isMRZEnable) // RecogType.MRZ
    
         if (sdkModel.isBankCardEnable)  // RecogType.BANKCARD
         
         if (sdkModel.isAllBarcodeEnable) // RecogType.BARCODE
    
        // sdkModel.isOCREnable is true then get card list which you are selected on creating license
        if (sdkModel.isOCREnable) List<ContryModel> modelList = recogEngine.getCardList(MainActivity.this);
        if (modelList != null) { // if country & card added in license
            ContryModel contryModel = modelList.get(selected country position);
            contryModel.getCountry_id(); // getting country id
            CardModel model = contryModel.getCards().get(0/*selected card position*/); // getting card
            model.getCard_id() // getting card id
            model.getCard_name()  // getting card name
    
            if (cardModel.getCard_type() == 1) {
                // RecogType.PDF417
            } else if (cardModel.getCard_type() == 2) {
                // RecogType.DL_PLATE
            } else {
                // RecogType.OCR
            }
        }
    }

    // Error Message if license is not valid.
    String licenseErrorMessage = sdkModel.message;
  2. After initializing the SDK, proceed to initialize the filters below if the license is valid.

    (sdkModel.i > 0)

    • Set Blur Percentage to allow blur on document

      //0 for clean document and 100 for Blurry document
      recogEngine.setBlurPercentage(Context context, int /*blurPercentage*/50);

    • Set Face blur Percentage to allow blur on detected Face

      // 0 for clean face and 100 for Blurry face
      recogEngine.setFaceBlurPercentage(Context context, int /*faceBlurPercentage*/50);

    • Set Glare Percentage to detect Glare on document

      // Set min and max percentage for glare
      recogEngine.setGlarePercentage(Context context, int /*minPercentage*/6, int /*maxPercentage*/98);

    • Set Hologram detection to verify the hologram on the face

      // true to check hologram on face
      recogEngine.SetHologramDetection(Context context, boolean /*isDetectHologram*/true);

    • Set light tolerance to detect light on document

      // 0 for full dark document and 100 for full bright document
      recogEngine.setLowLightTolerance(Context context, int /*tolerance*/30);

    • Set motion threshold to detect motion on camera document

        // 1 - allows 1% motion on document and
        // 100 - it can not detect motion and allow document to scan.
        recogEngine.setMotionThreshold(Context context, int /*motionThreshold*/18);

Step 3 : Set CameraView

  1. Your activity class should extend com.accurascan.ocr.mrz.motiondetection.SensorsActivity.

  2. Camera View support both orientations Portarait and Landscape

    Note: Make sure your activity orientation should be finalise before Initialize camera because auto rotate is not support during scanning.

  3. Initialize cameraView to your activity class.

    // defined object of CameraView
    private CameraView cameraView;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        if (isPortrait) {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); // to set portarait mode
        } else {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); // to set landscape mode
        }
        super.onCreate(savedInstanceState);
        setTheme(R.style.AppThemeNoActionBar);
        setContentView(R.layout.your layout);
    
        // Recog type selection base on your license data
        // As like RecogType.OCR, RecogType.MRZ, RecogType.PDF417, RecogType.DL_PLATE, RecogType.BANKCARD
        RecogType recogType = RecogType.OCR;
        cardId = CardModel.getCard_id();
        cardName = CardModel.getCard_name();
        countryId = ContryModel.getCountry_id();
    
        // initialized camera
        initCamera();
    }
    
    private void initCamera() {
        //<editor-fold desc="To get status bar height">
        Rect rectangle = new Rect();
        Window window = getWindow();
        window.getDecorView().getWindowVisibleDisplayFrame(rectangle);
        int statusBarTop = rectangle.top;
        int contentViewTop = window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
        int statusBarHeight = contentViewTop - statusBarTop;
        //</editor-fold>
    
        RelativeLayout linearLayout = findViewById(R.id.ocr_root); // layout width and height is match_parent
    
        cameraView = new CameraView(this);
        if (recogType == RecogType.OCR || recogType == RecogType.DL_PLATE) {
            // must have to set data for RecogType.OCR and RecogType.DL_PLATE
            cameraView.setCountryId(countryId).setCardId(cardId)
            		.setMinFrameForValidate(3/*minFrame*/); // Set min frame for qatar ID card for Most validated data. minFrame supports only odd numbers like 3,5...
        } else if (recogType == RecogType.PDF417) {
            // must have to set data RecogType.PDF417
            cameraView.setCountryId(countryId);
        }
        if (recogType == RecogType.MRZ) {
            // Also set MRZ document type to scan specific MRZ document
            // 1. ALL MRZ document       - MRZDocumentType.NONE        
            // 2. Passport MRZ document  - MRZDocumentType.PASSPORT_MRZ
            // 3. ID card MRZ document   - MRZDocumentType.ID_CARD_MRZ 
            // 4. Visa MRZ document      - MRZDocumentType.VISA_MRZ    
            cameraView.setMRZDocumentType(mrzDocumentType);
            
            // Pass 'all' for accepting MRZs of all countries
            // or you can pass respective country codes of countries whose MRZ you want to accept. Eg:- 'IND', 'USA', 'TUN', etc.
            cameraView.setMRZCountryCodeList("all");
        }
        cameraView.setRecogType(recogType)
                .setView(linearLayout) // To add camera view
                .setCameraFacing(0) // // To set selfie(1) or rear(0) camera.
                .setOcrCallback(this)  // To get feedback and Success Call back
                .setStatusBarHeight(statusBarHeight)  // To remove Height from Camera View if status bar visible
                .setFrontSide() // or cameraView.setBackSide(); to scan card side front or back default it's scan front side first
    //                Option setup
    //                .setEnableMediaPlayer(false) // false to disable default sound and true to enable sound and default it is true
    //                .setCustomMediaPlayer(MediaPlayer.create(this, /*custom sound file*/)) // To add your custom sound and Must have to enable media player
                .init();  // initialized camera
    	// To set barcode formate.
    	cameraView.setBarcodeFormat(int barcodeFormat); // access all type of BarcodeFormate from BarcodeFormat.java class
    }
    
    

    And recommended to override the following methods.

    /**
     * To handle camera on window focus update
     * @param hasFocus
     */
    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        if (cameraView != null) {
            cameraView.onWindowFocusUpdate(hasFocus);
        }
    }
    
    @Override
    protected void onResume() {
        super.onResume();
        cameraView.onResume();
    }
    
    @Override
    protected void onPause() {
        cameraView.onPause();
        super.onPause();
    }
    
    @Override
    protected void onDestroy() {
        cameraView.onDestroy();
        super.onDestroy();
    }

  4. Implements com.accurascan.ocr.mrz.interfaces.OcrCallback to your Activity and Override following methods to receive data during scanning.

    Note: Below Override methods are invoked from background thread. So make sure to use in UI thread

    • When below override method is getting called, you can start scanning and set parameter of center scanning frame.

      /**
       * To update your border frame according to width and height
       * it's different for different card
       * Call {@link CameraView#startOcrScan(boolean isReset)} To start Camera Preview
       * @param width    border layout width
       * @param height   border layout height
       */
      @Override
      public void onUpdateLayout(int width, int height) {
          if (cameraView != null) cameraView.startOcrScan(false);
      
          //<editor-fold desc="To set camera overlay Frame">
          ViewGroup.LayoutParams layoutParams = borderFrame.getLayoutParams();
          layoutParams.width = width;
          layoutParams.height = height;
          borderFrame.setLayoutParams(layoutParams);
      
          ViewGroup.LayoutParams lpRight = viewRight.getLayoutParams();
          lpRight.height = height;
          viewRight.setLayoutParams(lpRight);
      
          ViewGroup.LayoutParams lpLeft = viewLeft.getLayoutParams();
          lpLeft.height = height;
          viewLeft.setLayoutParams(lpLeft);
          //</editor-fold>
      }

    • You can receive information during scanning in the below override method

      /**
       * @param titleCode to display scan card message on top of border Frame
       *
       * @param errorMessage To display process message.
       *                null if message is not available
       * @param isFlip  true to set your customize animation for scan back card alert after complete front scan
       *                and also used cameraView.flipImage(ImageView) for default animation
       */
      @Override
      public void onProcessUpdate(int titleCode, String errorMessage, boolean isFlip) {
      // make sure update view on ui thread
          runOnUiThread(new Runnable() {
              @Override
              public void run() {
                  if (getTitleMessage(titleCode) != null) { // check
                      Toast.makeText(context, getTitleMessage(titleCode), Toast.LENGTH_SHORT).show(); // display title
                  }
                  if (errorMessage != null) {
                      Toast.makeText(context, getErrorMessage(errorMessage), Toast.LENGTH_SHORT).show(); // display message
                  }
                  if (isFlip) {
                      // To set default animation or remove this line to set your custom animation after successfully scan front side.
                      cameraView.flipImage(imageFlip);
                  }
              }
          });
      }
      
      private String getTitleMessage(int titleCode) {
          if (titleCode < 0) return null;
          switch (titleCode){
              case RecogEngine.SCAN_TITLE_OCR_FRONT:// for front side ocr;
                  return String.format("Scan Front Side of %s", cardName);
              case RecogEngine.SCAN_TITLE_OCR_BACK: // for back side ocr
                  return String.format("Scan Back Side of %s", cardName);
              case RecogEngine.SCAN_TITLE_OCR: // only for single side ocr
                  return String.format("Scan %s", cardName);
              case RecogEngine.SCAN_TITLE_MRZ_PDF417_FRONT:// for front side MRZ, PDF417 and BankCard
                  if (recogType == RecogType.BANKCARD) {
                      return "Scan Bank Card";
                  } else if (recogType == RecogType.BARCODE) {
                      return "Scan Barcode";
                  } else
                      return "Scan Front Side of Document";
              case RecogEngine.SCAN_TITLE_MRZ_PDF417_BACK: // for back side MRZ and PDF417
                  return "Now Scan Back Side of Document";
              case RecogEngine.SCAN_TITLE_DLPLATE: // for DL plate
                  return "Scan Number Plate";
              default:return "";
          }
      }
      
      private String getErrorMessage(String s) {
          switch (s) {
              case RecogEngine.ACCURA_ERROR_CODE_MOTION:
                  return "Keep Document Steady";
              case RecogEngine.ACCURA_ERROR_CODE_DOCUMENT_IN_FRAME:
                  return "Keep document in frame";
              case RecogEngine.ACCURA_ERROR_CODE_BRING_DOCUMENT_IN_FRAME:
                  return "Bring card near to frame.";
              case RecogEngine.ACCURA_ERROR_CODE_PROCESSING:
                  return "Processing...";
              case RecogEngine.ACCURA_ERROR_CODE_BLUR_DOCUMENT:
                  return "Blur detect in document";
              case RecogEngine.ACCURA_ERROR_CODE_FACE_BLUR:
                  return "Blur detected over face";
              case RecogEngine.ACCURA_ERROR_CODE_GLARE_DOCUMENT:
                  return "Glare detect in document";
              case RecogEngine.ACCURA_ERROR_CODE_HOLOGRAM:
                  return "Hologram Detected";
              case RecogEngine.ACCURA_ERROR_CODE_DARK_DOCUMENT:
                  return "Low lighting detected";
              case RecogEngine.ACCURA_ERROR_CODE_PHOTO_COPY_DOCUMENT:
                  return "Can not accept Photo Copy Document";
              case RecogEngine.ACCURA_ERROR_CODE_FACE:
                  return "Face not detected";
              case RecogEngine.ACCURA_ERROR_CODE_MRZ:
                  return "MRZ not detected";
              case RecogEngine.ACCURA_ERROR_CODE_PASSPORT_MRZ:
                  return "Passport MRZ not detected";
              case RecogEngine.ACCURA_ERROR_CODE_ID_MRZ:
                  return "ID card MRZ not detected";
              case RecogEngine.ACCURA_ERROR_CODE_VISA_MRZ:
                  return "Visa MRZ not detected";
              case RecogEngine.ACCURA_ERROR_CODE_WRONG_SIDE:
                  return "Scanning wrong side of document";
              case RecogEngine.ACCURA_ERROR_CODE_UPSIDE_DOWN_SIDE:
                  return "Document is upside down. Place it properly";
              default:
                  return s;
          }
      }
      

    Note : (Optional) cameraView.flipImage(imageFlip); Use to display default flip card animation. You can use your custom animation for flip card.

    • You can receive and display the scanned result in the below override method. The method below is invoked twice for RecogType.PDF417 and RecogType.OCR. And for the RecogType.OCR, it can be invoked once or twice with respect to a document. You can verify this with cameraView.isBackSideAvailable(). It will return true if the back is available, otherwise return false.

      /**
       * Override this method after scan complete to get data from document
       *
       * @param result is scanned card data
       *  result instance of {@link OcrData} if recog type is {@link com.docrecog.scan.RecogType#OCR}
       *              or {@link com.docrecog.scan.RecogType#DL_PLATE} or {@link com.docrecog.scan.RecogType#BARCODE}
       *  result instance of {@link RecogResult} if recog type is {@link com.docrecog.scan.RecogType#MRZ}
       *  result instance of {@link CardDetails} if recog type is {@link com.docrecog.scan.RecogType#BANKCARD}
       *  result instance of {@link PDF417Data} if recog type is {@link com.docrecog.scan.RecogType#PDF417}
       *
       */
      @Override
      public void onScannedComplete(Object result) {
          // display data on ui thread
          Log.e("TAG", "onScannedComplete: ");
          if (result != null) {
          	// make sure release camera view before open result screen
              // Do some code for display data
      
              if (result instanceof OcrData) {
                  if (recogType == RecogType.OCR) {
                      // @recogType is {@see com.docrecog.scan.RecogType#OCR}
                      if (isBack || !cameraView.isBackSideAvailable()) { // To check card has back side or not
                  	    if (cameraView != null) cameraView.release(true);	
                          OcrData.setOcrResult((OcrData) result); // Set data To retrieve it anywhere
                      } else {
                          isBack = true;
                          cameraView.setBackSide(); // To recognize data from back side too.
                          cameraView.flipImage(imageFlip);
                      }
                  } else if (recogType == RecogType.DL_PLATE || recogType == RecogType.BARCODE) {
                      // @recogType is {@link RecogType#DL_PLATE} or recogType == {@link RecogType#BARCODE}
                  	if (cameraView != null) cameraView.release(true);
                      OcrData.setOcrResult((OcrData) result); // Set data To retrieve it anywhere
                  }
              } else if (result instanceof RecogResult) {
                  // @recogType is {@see com.docrecog.scan.RecogType#MRZ}
                  if (cameraView != null) cameraView.release(true);
                  RecogResult.setRecogResult((RecogResult) result); // Set data To retrieve it anywhere
              } else if (result instanceof CardDetails) {
                  //  @recogType is {@see com.docrecog.scan.RecogType#BANKCARD}
                  if (cameraView != null) cameraView.release(true);
                  CardDetails.setCardDetails((CardDetails) result); // Set data To retrieve it anywhere
              } else if (result instanceof PDF417Data) {
                  //  @recogType is {@see com.docrecog.scan.RecogType#PDF417}
                  if (isBack || !cameraView.isBackSideAvailable()) {
                      if (cameraView != null) cameraView.release(true);
                      PDF417Data.setPDF417Result((PDF417Data) result); // Set data To retrieve it anywhere
                  } else {
                      isBack = true;
                      cameraView.setBackSide(); // To recognize data from back side too.
                      cameraView.flipImage(imageFlip);
                  }
              }
          } else Toast.makeText(this, "Failed", Toast.LENGTH_SHORT).show();
      }

    Note: It is necessary to release the camera view before showing the result on the results screen. Before releasing it, ensure that both sides of the document must be scanned as per your requirements. If you only scan one side and then release it directly, it may not fulfill your requirements.

    if (cameraView != null) cameraView.release(true);

    • Receive error messages

      @Override
      public void onError(String errorMessage) {
          // display data on ui thread
          // stop ocr if failed
          Runnable runnable = () -> Toast.makeText(OcrActivity.this, errorMessage, Toast.LENGTH_LONG).show();
          runOnUiThread(runnable);
      }

  5. (Optional)To restart the scanning process after obtaining the result, you need to include the following code. This code should be placed within the override method of an Android activity, which gets called when you open the result activity using the startActivityForResult(Intent, RESULT_ACTIVITY_CODE).

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        ...
        if (resultCode == RESULT_OK) {
            if (requestCode == RESULT_ACTIVITY_CODE) {
                //<editor-fold desc="Call CameraView#startOcrScan(true) to scan document again">
                if (cameraView != null) cameraView.startOcrScan(true);
                //</editor-fold>
            }
        }
    }

Last updated