Android实现扫一扫识别图像数字(使用训练的库拍照查看扫描结果)(下)

关于

  最近在整理电脑上面的项目,想起之前有研究学习图像数字识别功能实现,只记录了上篇,然后下半篇忘记写了,现在在回来看一下,有的地方自己也有些生疏了,总之也是借鉴了网上一部分。本篇代码内容较多,**不想细看的话可以直接跳到末尾,我会将源码放出来。**想知道如何训练数据的可以参考上一篇博文《Android实现扫一扫识别图像数字(镂空图像数字Tesseract训练)(上)》

效果图

在这里插入图片描述
  也可以下载apk试一下效果:
链接:https://pan.baidu.com/s/1TA2o4ABt3bnqjTAA1gIpjQ
提取码:1234
  当然了,识别效果不是每次都正确的,因为训练库里面的数据不够庞大,所以误差率还是不小的,不然如果想要正式使用的话,有大量的训练数据就没关系了

第一步,添加我们的训练库

在res/下新建raw文件夹,将我们上篇训练的num.traineddata拷贝进去:
在这里插入图片描述
  这里我把我的训练好的数据放到网盘里:

链接:https://pan.baidu.com/s/1ekvpF6nZbPfNOxJGpOTjOg
 提取码:1234

编写扫描框控件

public final class ScannerFinderView extends RelativeLayout {
   
   

    private static final int[] SCANNER_ALPHA = {
   
    0, 64, 128, 192, 255, 192, 128, 64 };
    private static final long ANIMATION_DELAY = 100L;
    private static final int OPAQUE = 0xFF;

    private static final int MIN_FOCUS_BOX_WIDTH = 50;
    private static final int MIN_FOCUS_BOX_HEIGHT = 50;
    private static final int MIN_FOCUS_BOX_TOP = 200;

    private static Point ScrRes;
    private int top;

    private Paint mPaint;
    private int mScannerAlpha;
    private int mMaskColor;
    private int mFrameColor;
    private int mLaserColor;
    private int mTextColor;
    private int mFocusThick;
    private int mAngleThick;
    private int mAngleLength;

    private Rect mFrameRect; //绘制的Rect
    private Rect mRect; //返回的Rect

    public ScannerFinderView(Context context) {
   
   
        this(context, null);
    }

    public ScannerFinderView(Context context, AttributeSet attrs) {
   
   
        this(context, attrs, 0);
    }

    public ScannerFinderView(Context context, AttributeSet attrs, int defStyleAttr) {
   
   
        super(context, attrs, defStyleAttr);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        Resources resources = getResources();
        mMaskColor = resources.getColor(R.color.finder_mask);
        mFrameColor = resources.getColor(R.color.finder_frame);
        mLaserColor = resources.getColor(R.color.finder_laser);
        mTextColor = resources.getColor(R.color.white);

        mFocusThick = 1;
        mAngleThick = 8;
        mAngleLength = 40;
        mScannerAlpha = 0;
        init(context);
        this.setOnTouchListener(getTouchListener());
    }

    private void init(Context context) {
   
   
        if (isInEditMode()) {
   
   
            return;
        }
        // 需要调用下面的方法才会执行onDraw方法
        setWillNotDraw(false);

        if (mFrameRect == null) {
   
   

            ScrRes = ScreenUtils.getScreenResolution(context);

            int width = ScrRes.x * 3 / 5;
            int height = width;

            width = width == 0
                    ? MIN_FOCUS_BOX_WIDTH
                    : width < MIN_FOCUS_BOX_WIDTH ? MIN_FOCUS_BOX_WIDTH : width;

            height = height == 0
                    ? MIN_FOCUS_BOX_HEIGHT
                    : height < MIN_FOCUS_BOX_HEIGHT ? MIN_FOCUS_BOX_HEIGHT : height;

            int left = (ScrRes.x - width) / 2;
            int top = (ScrRes.y - height) / 5;
            this.top = top; //记录初始距离上方距离

            mFrameRect = new Rect(left, top, left + width, top + height);
            mRect = mFrameRect;
        }
    }

    public Rect getRect() {
   
   
        return mRect;
    }

    @Override
    public void onDraw(Canvas canvas) {
   
   
        if (isInEditMode()) {
   
   
            return;
        }
        Rect frame = mFrameRect;
        if (frame == null) {
   
   
            return;
        }
        int width = canvas.getWidth();
        int height = canvas.getHeight();

        // 绘制焦点框外边的暗色背景
        mPaint.setColor(mMaskColor);
        canvas.drawRect(0, 0, width, frame.top, mPaint);
        canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, mPaint);
        canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, mPaint);
        canvas.drawRect(0, frame.bottom + 1, width, height, mPaint);

        drawFocusRect(canvas, frame);
        drawAngle(canvas, frame);
        drawText(canvas, frame);
        drawLaser(canvas, frame);
    }

    /**
     * 画聚焦框,白色的
     *
     * @param canvas
     * @param rect
     */
    private void drawFocusRect(Canvas canvas, Rect rect) {
   
   
        // 绘制焦点框(黑色)
        mPaint.setColor(mFrameColor);
        // 上
        canvas.drawRect(rect.left + mAngleLength, rect.top, rect.right - mAngleLength, rect.top + mFocusThick, mPaint);
        // 左
        canvas.drawRect(rect.left, rect.top + mAngleLength, rect.left + mFocusThick, rect.bottom - mAngleLength,
                mPaint);
        // 右
        canvas.drawRect(rect.right - mFocusThick, rect.top + mAngleLength, rect.right, rect.bottom - mAngleLength,
                mPaint);
        // 下
        canvas.drawRect(rect.left + mAngleLength, rect.bottom - mFocusThick, rect.right - mAngleLength, rect.bottom,
                mPaint);
    }

    /**
     * 画四个角
     *
     * @param canvas
     * @param rect
     */
    private void drawAngle(Canvas canvas, Rect rect) {
   
   
        mPaint.setColor(mLaserColor);
        mPaint.setAlpha(OPAQUE);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStrokeWidth(mAngleThick);
        int left = rect.left;
        int top = rect.top;
        int right = rect.right;
        int bottom = rect.bottom;
        // 左上角
        canvas.drawRect(left, top, left + mAngleLength, top + mAngleThick, mPaint);
        canvas.drawRect(left, top, left + mAngleThick, top + mAngleLength, mPaint);
        // 右上角
        canvas.drawRect(right - mAngleLength, top, right, top + mAngleThick, mPaint);
        canvas.drawRect(right - mAngleThick, top, right, top + mAngleLength, mPaint);
        // 左下角
        canvas.drawRect(left, bottom - mAngleLength, left + mAngleThick, bottom, mPaint);
        canvas.drawRect(left, bottom - mAngleThick, left + mAngleLength, bottom, mPaint);
        // 右下角
        canvas.drawRect(right - mAngleLength, bottom - mAngleThick, right, bottom, mPaint);
        canvas.drawRect(right - mAngleThick, bottom - mAngleLength, right, bottom, mPaint);
    }

    private void drawText(Canvas canvas, Rect rect) {
   
   
        int margin = 40;
        mPaint.setColor(mTextColor);
        mPaint.setTextSize(getResources().getDimension(R.dimen.text_size_13sp));  //13dp
        String text = getResources().getString(R.string.auto_scan_notification); //<stringname="auto_scan_notification">将扫描内容放入框内,即可自动扫描</string>
        Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
        float fontTotalHeight = fontMetrics.bottom - fontMetrics.top;
        float offY = fontTotalHeight / 2 - fontMetrics.bottom;
        float newY = rect.bottom + margin + offY;
        float left = (ScreenUtils.getScreenWidth() - mPaint.getTextSize() * text.length()) / 2;
        canvas.drawText(text, left, newY, mPaint);
    }

    private void drawLaser(Canvas canvas, Rect rect) {
   
   
        // 绘制焦点框内固定的一条扫描线
        mPaint.setColor(mLaserColor);
        mPaint.setAlpha(SCANNER_ALPHA[mScannerAlpha]);
        mScannerAlpha = (mScannerAlpha + 1) % SCANNER_ALPHA.length;
        int middle = rect.height() / 2 + rect.top;
        canvas.drawRect(rect.left + 2, middle - 1, rect.right - 1, middle + 2, mPaint);

        mHandler.sendEmptyMessageDelayed(1, ANIMATION_DELAY);
    }

    private Handler mHandler = new Handler(){
   
   
        @Override
        public void handleMessage(Message msg) {
   
   
            super.handleMessage(msg);
            invalidate();
        }
    };

    private OnTouchListener touchListener;

    private OnTouchListener getTouchListener() {
   
   

        if (touchListener == null){
   
   
            touchListener = new OnTouchListener() {
   
   

                int lastX = -1;
                int lastY = -1;

                @Override
                public boolean onTouch(View v, MotionEvent event) {
   
   
                    switch (event.getAction()) {
   
   
                        case MotionEvent.ACTION_DOWN:
                            lastX = -1;
                            lastY = -1;
                            return true;
                        case MotionEvent.ACTION_MOVE:
                            int currentX = (int) event.getX();
                            int currentY = (int) event.getY();
                            try {
   
   
                                Rect rect = mFrameRect;
                                final int BUFFER = 60;
                                if (lastX >= 0) {
   
   
                                    
                                    boolean currentXLeft = currentX >= rect.left - BUFFER && currentX <= rect.left + BUFFER;
                                    boolean currentXRight = currentX >= rect.right - BUFFER && currentX <= rect.right + BUFFER;
                                    boolean lastXLeft = lastX >= rect.left - BUFFER && lastX <= rect.left + BUFFER;
                                    boolean lastXRight = lastX >= rect.right - BUFFER && lastX <= rect.right + BUFFER;
                                    
                                    boolean currentYTop = currentY <= rect.top + BUFFER && currentY >= rect.top - BUFFER;
                                    boolean currentYBottom = currentY <= rect.bottom + BUFFER && currentY >= rect.bottom - BUFFER;
                                    boolean lastYTop = lastY <= rect.top + BUFFER && lastY >= rect.top - BUFFER;
                                    boolean lastYBottom = lastY <= rect.bottom + BUFFER && lastY >= rect.bottom - BUFFER;
                                    
                                    boolean XLeft = currentXLeft || lastXLeft;
                                    boolean XRight = currentXRight || lastXRight;
                                    boolean YTop = currentYTop || lastYTop;
                                    boolean YBottom = currentYBottom || lastYBottom;
                                    
                                    boolean YTopBottom = (currentY <= rect.bottom && currentY >= rect.top)
                                            || (lastY <= rect.bottom && lastY >= rect.top);

                                    boolean XLeftRight = (currentX <= rect.right && currentX >= rect.left)
                                            || (lastX <= rect.right && lastX >= rect.left);
                                            
                                        //右上角
                                    if (XLeft && YTop) {
   
    
                                        updateBoxRect(2 * (lastX - currentX), (lastY - currentY), true); 
                                        //左上角
                                    } else if (XRight && YTop) {
   
   
                                        updateBoxRect(2 * (currentX - lastX), (lastY - currentY), true);
                                        //右下角
                                    } else if (XLeft && YBottom) {
   
   
                                        updateBoxRect(2 * (lastX - currentX), (currentY - lastY), false);
                                        //左下角
                                    } else if (XRight && YBottom) {
   
   
                                        updateBoxRect(2 * (currentX - lastX), (currentY - lastY), false);
                                        //左侧
                                    } else if (XLeft && YTopBottom) {
   
    
                                        updateBoxRect(2 * (lastX - currentX), 0, false);
                                        //右侧
                                    } else if (XRight && YTopBottom) {
   
    
                                        updateBoxRect(2 * (currentX - lastX), 0, false);
                                        //上方
                                    } else if (YTop && XLeftRight) {
   
    
                                        updateBoxRect(0, (lastY - currentY), true);
                                        //下方
                                    } else if (YBottom && XLeftRight) {
   
   
                                        updateBoxRect(0, (currentY - lastY), false);
                                    }
                                }
                            } catch (NullPointerException e) {
   
   
                                e.printStackTrace();
                            }
                            v.invalidate();
                            lastX = currentX;
                            lastY = currentY;
                            return true;
                        case MotionEvent.ACTION_UP:
                            //移除之前的刷新
                            mHandler.removeMessages(1);
                            //松手时对外更新
                            mRect = mFrameRect; 
                            lastX = -1;
                            lastY = -1;
                            return true;
                        default:
                            
                    }
                    return false;
                }
            };
        }

        return touchListener;
    }

    private void updateBoxRect(int dW, int dH, boolean isUpward) {
   
   

        int newWidth = (mFrameRect.width() + dW > ScrRes.x - 4 || mFrameRect.width() + dW < MIN_FOCUS_BOX_WIDTH)
                ? 0 : mFrameRect.width() + dW;

        //限制扫描框最大高度不超过屏幕宽度
        int newHeight = (mFrameRect.height() + dH > ScrRes.x || mFrameRect.height() + dH < MIN_FOCUS_BOX_HEIGHT)
                ? 0 : mFrameRect.height() + dH;

        int leftOffset = (ScrRes.x - newWidth) / 2;

        if (isUpward){
   
   
            this.top -= dH;
        }

        int topOffset = this.top;

        if (topOffset < MIN_FOCUS_BOX_TOP){
   
   
            this.top = MIN_FOCUS_BOX_TOP;
            return;
        }

        if (topOffset + newHeight > MIN_FOCUS_BOX_TOP + ScrRes.x){
   
   
            return;
        }

        if (newWidth < MIN_FOCUS_BOX_WIDTH || newHeight < MIN_FOCUS_BOX_HEIGHT){
   
   
            return;
        }

        mFrameRect = new Rect(leftOffset, topOffset, leftOffset + newWidth, topOffset + newHeight);
    }

    @Override
    protected void onDetachedFromWindow() {
   
   
        super.onDetachedFromWindow();
        mHandler.removeMessages(1);
    }
}

 对应的颜色代码:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="white">#FFFFFFFF</color>
    <color name="finder_mask">#80000000</color>
    <color name="finder_frame">#FFFFFFFF</color>
    <color name="finder_laser">#0db8f6</color>
</resources>

 获取屏幕尺寸的帮助类ScreenUtils:

/**
 * ScreenUtils
 */
public class ScreenUtils {
   
   

    private ScreenUtils() {
   
   
        throw new AssertionError();
    }

    /**
     * 获取屏幕宽度
     *
     * @return
     */
    public static int getScreenWidth() {
   
   
        Context context = MyApplication.sAppContext;
        DisplayMetrics dm = context.getResources().getDisplayMetrics();
        return dm.widthPixels;
    }

    /**
     * 获取屏幕高度
     *
     * @return
     */
    public static int getScreenHeight() {
   
   
        Context context = MyApplication.sAppContext;
        DisplayMetrics dm = context.getResources().getDisplayMetrics();
        return dm.heightPixels;
    }

    public static Point getScreenResolution(Context context) {
   
   

        WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Display display = manager.getDefaultDisplay();

        int width = display.getWidth();
        int height = display.getHeight();
        return new Point(width, height);
    }
}

新建扫码界面ScannerActivity.java

 新建一个页面ScannerActivity,其中ScannerActivity.xml布局如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ViewStub
        android:id="@+id/qr_code_view_stub"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"/>

    <TextView
        android:id="@+id/qr_code_header_bar"
        android:layout_width="match_parent"
        android:gravity="center"
        android:layout_height="@dimen/title_bar_height"
        android:background="@android:color/black"
        android:text="@string/title_activity_scan_qr_code"
        android:textColor="@color/white"
        android:textSize="18sp" />

    <com.zl.tesseract.scanner.view.ScannerFinderView
        android:id="@+id/qr_code_view_finder"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"
        android:visibility="gone"/>

    <View
        android:layout_below="@id/qr_code_header_bar"
        android:id="@+id/qr_code_view_background"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/black"
        android:visibility="gone"/>

    <Switch
        android:id="@+id/switch1"
        android:text="@string/is_qr_code_scanner"
        android:layout_margin="20dp"
        android:layout_alignParentBottom="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>


    <Switch
        android:id="@+id/switch2"
        android:text="@string/is_open_flashlight"
        android:layout_margin="20dp"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

雪の星空朝酱

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

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

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

打赏作者

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

抵扣说明:

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

余额充值