V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
pqpo
V2EX  ›  程序员

SmartCamera 高性能相机实时采集识别框架, 支持算法可配置化调优

  •  1
     
  •   pqpo · 2018-08-27 16:19:20 +08:00 · 1541 次点击
    这是一个创建于 2059 天前的主题,其中的信息可能已经有所发展或是发生改变。

    English

    SmartCamera 是一个 Android 相机拓展库,提供了一个高度可定制的实时扫描模块能够实时采集并且识别相机内物体边框是否吻合指定区域。如果觉得还不错,欢迎 star,fork。

    语言描述起来略显生涩,具体实现的功能如下图所示,适用于身份证,名片,文档等内容的扫描、自动拍摄并且裁剪, 你也可以下载 apk 体验:

    SmartCamera-Sample-debug.apk

    在相机实现上,SmartCamera 以源码的方式引用了 Google 开源的 CameraView ,并且稍作修改以支持 Camera.PreviewCallback 回调来获取相机预览流。

    SmartCameraView 继承于修改后的 CameraView,为其添加了一个选框蒙版视图( MaskView )和一个实时扫描模块( SmartScanner )。其中选框视图即是你看到的相机上面的那层选取框,并配备了一个由上到下的扫描效果,当然你也可以实现 MaskViewImpl 接口来自定义选框视图。

    实时扫描模块( SmartScanner )是本库的核心功能所在,配合相机 PreviewCallback 接口回调的预览流和选框视图 MaskView 提供的选框区域 RectF,能以不错的性能实时判断出内容是否吻合选框

    你也可以关注我的另一个库 SmartCropper: 一个简单易用的智能图片裁剪库,适用于身份证,名片,文档等照片的裁剪。

    扫描算法调优

    SmartScanner 提供了丰富的算法配置,使用者可以自己修改扫描算法以获得更好的适配性,阅读附录一提供的各参数使用说明来获得更好的识别效果。

    为了更方便、高效地调优算法,SmartScanner 贴心地为你提供了扫描预览模式,开启预览功能后,你可以通过 SmartScanner 获取每一帧处理的结果输出到 ImageView 中实时观察 native 层扫描的结果,其中白线区域即为边缘检测的结果,白线加粗区域即为识别出的边框。

    你的目标是通过调节 SmartScanner 的各个参数使得内容边界清晰可见,识别出的边框(白色加粗线段)准确无误

    注:SmartCamera 在各方面做了性能以及内存上的优化,但是出于不必要的性能资源浪费,算法参数调优结束后请关闭预览模式。

    接入

    1.根目录下的 build.gradle 添加:

    allprojects {
            repositories {
                ...
                maven { url 'https://jitpack.io' }
            }
    }
    

    2.添加依赖

    dependencies {
          implementation 'com.github.pqpo:SmartCamera:v1.0.0'
    }
    

    注意:由于使用了 JNI, 请避免混淆

    -keep class me.pqpo.smartcameralib.**{*;}
    

    使用

    1. 引入相机布局,并启动相机(必要时启动预览)

    <me.pqpo.smartcameralib.SmartCameraView
            android:id="@+id/camera_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    
    @Override
    protected void onResume() {
       super.onResume();
       mCameraView.start();
       mCameraView.startScan();
    }
    
    
    @Override
    protected void onPause() {
       mCameraView.stop();
       super.onPause();
       if (alertDialog != null) {
           alertDialog.dismiss();
       }
       mCameraView.stopScan();
    }
    

    注:若开启了预览别忘了调用相应开启、结束预览的方法。

    2. 修改扫描模块参数(可选,调优算法,同时按第 4 步中开启预览模式)

    扫描模块各个参数含义详见附录一
    
    private void initScannerParams() {
         SmartScanner.DEBUG = true;
         SmartScanner.detectionRatio = 0.1f;
         SmartScanner.checkMinLengthRatio = 0.8f;
         SmartScanner.cannyThreshold1 = 20;
         SmartScanner.cannyThreshold2 = 50;
         SmartScanner.houghLinesThreshold = 130;
         SmartScanner.houghLinesMinLineLength = 80;
         SmartScanner.houghLinesMaxLineGap = 10;
         SmartScanner.firstGaussianBlurRadius = 3;
         SmartScanner.secondGaussianBlurRadius = 3;
         SmartScanner.maxSize = 300;
         SmartScanner.angleThreshold = 5;
         // don't forget reload params
         SmartScanner.reloadParams();
    }
    

    注: 修改参数后别忘记通知 native 层重新加载参数:SmartScanner.reloadParams();

    3. 配置蒙版选框视图(可选,若要修改默认的视图, 或要修改选框区域)

    配置 MaskView 各个方法的含义详见附录二
    
    final MaskView maskView = (MaskView) mCameraView.getMaskView();;
    maskView.setMaskLineColor(0xff00adb5);
    maskView.setShowScanLine(true);
    maskView.setScanLineGradient(0xff00adb5, 0x0000adb5);
    maskView.setMaskLineWidth(2);
    maskView.setMaskRadius(5);
    maskView.setScanSpeed(6);
    maskView.setScanGradientSpread(80);
    mCameraView.post(new Runnable() {
          @Override
          public void run() {
              int width = mCameraView.getWidth();
              int height = mCameraView.getHeight();
              if (width < height) {
                  maskView.setMaskSize((int) (width * 0.6f), (int) (width * 0.6f / 0.63));
                  maskView.setMaskOffset(0, -(int)(width * 0.1));
               } else {
                  maskView.setMaskSize((int) (width * 0.6f), (int) (width * 0.6f * 0.63));
               }
          }
    });
    mCameraView.setMaskView(maskView);
            
    

    4. 配置 SmartCameraView

    1. 开启预览:

    mCameraView.getSmartScanner().setPreview(true);
    mCameraView.setOnScanResultListener(new SmartCameraView.OnScanResultListener() {
          @Override
          public boolean onScanResult(SmartCameraView smartCameraView, int result) {
              Bitmap previewBitmap = smartCameraView.getPreviewBitmap();
              if (previewBitmap != null) {
                 ivPreview.setImageBitmap(previewBitmap);
              }
              return false;
          }
    });
    

    通过第一句代码开启了预览模式。
    你可以通过 setOnScanResultListener 设置回调获得每一帧的扫描结果,其中 result == 1 表示识别结果吻合边框
    若开启了预览模式,你可以在回调中使用 smartCameraView.getPreviewBitmap() 方法获取每一帧处理的结果。
    返回值为 false 表示不拦截扫描结果,这时 SmartCameraView 内部会在 result 为 1 的情况下自动触发拍照,若你自己处理了扫描结果返回 true 即可。

    2. 获取拍照结果,并且裁剪选框区域:

    mCameraView.addCallback(new CameraView.Callback() {
         @Override
         public void onPictureTaken(CameraView cameraView, byte[] data) {
              super.onPictureTaken(cameraView, data);
              // 异步裁剪图片
              mCameraView.cropImage(data, new SmartCameraView.CropCallback() {
                  @Override
                  public void onCropped(Bitmap cropBitmap) {
                      if (cropBitmap != null) {
                          showPicture(cropBitmap);
                      }
                  }
           	);
       }
    });
    

    获取拍照结果的回调是 CameraView 提供的,你只需要在内部调用 SmartCameraView 提供的 cropImage 方法即可获取选框区域内的裁剪图片

    注:其他关于 SmartCameraView 的使用方法同 CameraView ,另外更具体的使用方法请参考 app 内代码

    附录

    见 github

    感谢


    关于我:

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1356 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 23:35 · PVG 07:35 · LAX 16:35 · JFK 19:35
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.