android 微信二维码识别,二维码图像校正算法

之前集成的zxing二维码扫描模型,正常的二维码都可以识别出来,但是识别速度不怎么快,对于特殊的二维码,比如有磨损、光线不足的二维码就扫描不出来了。后来测试发现用浏览器、微信都可以扫描到。于是在github、码云上找了好几个二维码扫描的库,但是运行起来后发现都不能识别出来。最后发现一个基于OpenCV开源的微信二维码引擎移植封装的二维码识别库,装上apk试着扫描了一下,发现可以识别,内心无比激动,真的很感谢博主可以把源码开源出来。

这里我附几个二维码,大家感兴趣的话可以试试扫描效果:

二维码编码:0490
二维码编码:0429
二维码编码:0049

导入mudule

 引用module依赖

    implementation project(path: ':opencv')
    implementation project(path: ':opencv-armv7a')
    implementation project(path: ':wechat-qrcode')
    implementation project(path: ':wechat-qrcode-scanning')

java版本

java11或者java17

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
    }

ABI过滤

 defaultConfig {
 
     //...
     
     ndk {
         //设置支持的 SO 库架构(开发者可以根据需要,选择一个或多个平台的 so)
         abiFilters 'armeabi-v7a' // , 'arm64-v8a', 'x86', 'x86_64'
     }
 }

初始化sdk

        // 初始化OpenCV
        OpenCV.initOpenCV();
        // 初始化WeChatQRCodeDetector
        WeChatQRCodeDetector.init(this);

WeChatCameraScanActivity

public class WeChatCameraScanActivity extends BaseCameraScanActivity<List<String>> {

    protected ViewfinderView viewfinderView;

    @Override
    public void initUI() {
        int viewfinderViewId = getViewfinderViewId();
        if (viewfinderViewId != View.NO_ID && viewfinderViewId != 0) {
            viewfinderView = findViewById(viewfinderViewId);
        }
        super.initUI();
    }

    @Nullable
    @Override
    public Analyzer<List<String>> createAnalyzer() {
        return new WeChatScanningAnalyzer();
    }

    /**
     * 布局ID;通过覆写此方法可以自定义布局
     *
     * @return 布局ID
     */
    @Override
    public int getLayoutId() {
        return com.king.wechat.qrcode.scanning.R.layout.wechat_camera_scan;
    }

    /**
     * {@link #viewfinderView} 的 ID
     *
     * @return 默认返回{@code R.id.viewfinderView}, 如果不需要扫码框可以返回{@link View#NO_ID}
     */

    public int getViewfinderViewId() {
        return com.king.wechat.qrcode.scanning.R.id.viewfinderView;
    }

    @Override
    public void onScanResultCallback(@NonNull AnalyzeResult<List<String>> result) {

    }
}

MainActivity

public class MainActivity extends WeChatCameraScanActivity {

    private static final String TAG = "MainActivityTag";
    protected ImageView ivResult;
    private Timer delayTimer;

    @Override
    public void initUI() {
        super.initUI();
        ivResult = findViewById(R.id.ivResult);
        delayTimer = new Timer();
    }

    @Override
    public int getLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    public void onScanResultCallback(@NonNull AnalyzeResult<List<String>> result) {
        super.onScanResultCallback(result);
        // 停止分析
        getCameraScan().setAnalyzeImage(false);
        Log.d(TAG, result.getResult().toString());

        // 当初始化 WeChatScanningAnalyzer 时,如果是需要二维码的位置信息,则可通过 WeChatScanningAnalyzer.QRCodeAnalyzeResult 获取
        // 如果需要处理结果二维码的位置信息
        if (result instanceof WeChatScanningAnalyzer.QRCodeAnalyzeResult) {
            ivResult.setImageBitmap(previewView.getBitmap());
            int width = result.getBitmapWidth();
            int height = result.getBitmapHeight();
            List<Point> points = new ArrayList<>();
            List<Mat> matList = ((WeChatScanningAnalyzer.QRCodeAnalyzeResult<List<String>>) result).getPoints();

            Bitmap bitmap = result.getBitmap();
            BitmapUtils.drawRectOnBitmap(bitmap, (canvas, paint) -> {
                if (matList != null) {
                    for (Mat mat : matList) {
                        Point point0 = new Point((int) mat.get(0, 0)[0], (int) mat.get(0, 1)[0]);
                        Point point1 = new Point((int) mat.get(1, 0)[0], (int) mat.get(1, 1)[0]);
                        Point point2 = new Point((int) mat.get(2, 0)[0], (int) mat.get(2, 1)[0]);
                        Point point3 = new Point((int) mat.get(3, 0)[0], (int) mat.get(3, 1)[0]);
                        int centerX = (point0.x + point1.x + point2.x + point3.x) / 4;
                        int centerY = (point0.y + point1.y + point2.y + point3.y) / 4;
                        //将实际的结果中心点坐标转换成界面预览的坐标
                        Point point = PointUtils.transform(
                                centerX,
                                centerY,
                                width,
                                height,
                                viewfinderView.getWidth(),
                                viewfinderView.getHeight()
                        );
                        points.add(point);

                        Path path = new Path();
                        path.moveTo((float) mat.get(0, 0)[0], (float) mat.get(0, 1)[0]);
                        path.lineTo((float) mat.get(1, 0)[0], (float) mat.get(1, 1)[0]);
                        path.lineTo((float) mat.get(2, 0)[0], (float) mat.get(2, 1)[0]);
                        path.lineTo((float) mat.get(3, 0)[0], (float) mat.get(3, 1)[0]);
                        path.lineTo((float) mat.get(0, 0)[0], (float) mat.get(0, 1)[0]);
                        // 将二维码位置在图片上框出来
                        canvas.drawPath(path, paint);

                    }
                    //设置Item点击监听
                    viewfinderView.setOnItemClickListener(position -> {
                        String resultOk = result.getResult().get(position);
                        Toast.makeText(MainActivity.this, resultOk, Toast.LENGTH_SHORT).show();
                    });
                    //显示结果点信息
                    viewfinderView.showResultPoints(points);
                    if (result.getResult().size() == 1) {
                        Toast.makeText(MainActivity.this, "ok-one:" + result.getResult().get(0), Toast.LENGTH_SHORT).show();
                    }
                }
            });


        } else {
            Toast.makeText(this, "ok-two:" + result.getResult().get(0), Toast.LENGTH_SHORT).show();
        }


        delayTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        ivResult.setImageResource(0);
                        viewfinderView.showScanner();
                        getCameraScan().setAnalyzeImage(true);
                    }
                });

            }
        }, 2000);
    }


    @Nullable
    @Override
    public Analyzer<List<String>> createAnalyzer() {
        return new WeChatScanningAnalyzer(true);
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        if (viewfinderView.isShowPoints()) {// 如果是结果点显示时,用户点击了返回键,则认为是取消选择当前结果,重新开始扫码
            ivResult.setImageResource(0);
            viewfinderView.showScanner();
            getCameraScan().setAnalyzeImage(true);
        }
    }


}

BitmapUtils

public class BitmapUtils {

    private static final String TAG = "BitmapUtils";

    public static Bitmap drawRectOnBitmap(Bitmap sourceBitmap, Block block) {
        int width = sourceBitmap.getWidth();
        int height = sourceBitmap.getHeight();
        Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(result);
        canvas.drawBitmap(sourceBitmap, 0, 0, null);

        Paint paint = new Paint();
        paint.setStrokeWidth(6);
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.RED);

        try {
            if (block != null) {
                block.invoke(canvas, paint);
            }
        } catch (Exception e) {
            Log.w(TAG, e.getMessage());
        }

        return result;
    }

    public interface Block {
        void invoke(Canvas canvas, Paint paint);
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.camera.view.PreviewView
        android:id="@+id/previewView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    
    <ImageView
        android:id="@+id/ivResult"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <com.king.view.viewfinderview.ViewfinderView
        android:id="@+id/viewfinderView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:vvLaserStyle="line"/>

    <ImageView
        android:id="@+id/ivFlashlight"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="@dimen/camera_scan_flashlight_margin_top"
        android:contentDescription="@null"
        android:src="@drawable/camera_scan_flashlight_selector" />

</FrameLayout>

自己改的Java调用的Demo: https://gitee.com/baipenggui/we-chat-code-demo

原文地址:WeChatQRCode: ⛄ 基于OpenCV开源的微信二维码引擎移植的Android扫码识别库

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

窗台的花花

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值