微信小程序QCR技术

473 阅读3分钟

1、场景介绍

什么情况下需要用到小程序的QCR技术,无非是身份证/银行卡等信息的图片识别场景下需要用到。下文介绍QCR在微信小程序中的功能实现。下文主要讲解微信小程序QCR插件识别

源码地址:gitee.com/acher_Saber…

2、使用微信开发接口实现

【注意】因为是服务端的接口,所以做好是放在后端做请求,因为放在前端容易暴露APPID和AppSecret,有风险的

微信小程序开发者文档:developers.weixin.qq.com/miniprogram…

  1. 首先获取access_token

官方文档:developers.weixin.qq.com/miniprogram… Image.png

示例代码

    /**
     * @description: 获取access_token,用于证件识别
     * @param {小程序的appID}  APPID
     * @param {输入AppSecret}  AppSecret
     * @return {获取access_token}
     */
    getAccessToken(APPID = 'APPID', AppSecret = 'AppSecret') {
        return new Promise((resolve, reject) => {
            wx.request({
                method: 'get',
                url: `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${AppSecret}`,
                success(res) {
                    resolve(res)
                },
                fail(res) {
                    reject(res)
                }
            })
        })
    }
  1. 调用QCR证件识别方法

官方文档:developers.weixin.qq.com/miniprogram…

    /**
     * @description: 微信小程序服务端api调用识别身份证
     * 官方文档:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/ocr/ocr.idcard.html
     * @param {生成的accessToken}  accessToken
     * @param {输入金额值, string}  img_url  要检测的图片 url,传这个则不用传 img 参数。
     * @param {输入金额值, FormData}  img  form-data 中媒体文件标识,有filename、filelength、content-type等信息,传这个则不用传 img_url。
     * @return {获取access_token}
     */
     idCardQCR(accessToken, img_url, img) {
        return new Promise((resolve, reject) => {
            wx.request({
                method: 'post',
                url: `https://api.weixin.qq.com/cv/ocr/idcard?type=MODE&img_url=${img_url}&access_token=${accessToken}`,
                success(res) {
                    console.log('识别证件',res)
                    if (res.errMsg === "request:ok") {
                        resolve(res.data)
                    } else {
                        wx.showToast({
                            title: '获取access_token失败!',
                            icon: 'none'
                        })
                    }
                },
                fail(res) {
                    wx.showToast({
                        title: '获取access_token失败!',
                        icon: 'none'
                    })
                    reject(res)
                }
            })
        })
    }

请求失败:

Image.png

原因是

我们需要区微信服务平台去购买免费的100次/天:fuwu.weixin.qq.com/service/det…

OCR识别案例: developers.weixin.qq.com/community/d…

Image.png

识别成功 Image.png

整体代码为:

    /**
     * @description: 获取access_token,用于证件识别
     * @param {小程序的appID}  APPID
     * @param {输入AppSecret}  AppSecret
     * @return {获取access_token}
     */
     getAccessToken(APPID = 'APPID', AppSecret = 'AppSecret') {
        return new Promise((resolve, reject) => {
            wx.request({
                method: 'get',
                url: `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${AppSecret}`,
                success(res) {
                    if (res.errMsg === "request:ok") {
                        resolve(res.data)
                    } else {
                        wx.showToast({
                            title: '获取access_token失败!',
                            icon: 'none'
                        })
                    }
                },
                fail(res) {
                    wx.showToast({
                        title: '获取access_token失败!',
                        icon: 'none'
                    })
                    reject(res)
                }
            })
        })
    },

    /* 身份证---正反面 */
    // 正面:  http://3pl.dekuncn.com//upload/2021-12-22/20211222030944214AH90TN8.jpg
    // 反面:   http://3pl.dekuncn.com//upload/2021-12-15/2021121504002872RJBKDEFO.jpg

    /* 驾驶证 */
    // http://3pl.dekuncn.com//upload/2021-12-22/2021122203124441CS8EOW7P.jpg

    /* 行驶证 */
    // http://3pl.dekuncn.com//upload/2021-12-22/2021122203123967IT9U0XBO.jpg

    /* 银行卡 */
    // https://gimg2.baidu.com/image_search/src=http%3A%2F%2Finews.gtimg.com%2Fnewsapp_bt%2F0%2F13770567688%2F641.jpg&refer=http%3A%2F%2Finews.gtimg.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1642750676&t=605fb88baf0b654fe3badfcad7937104


    /**
     * @description: 微信小程序服务端api调用识别身份证
     * 官方文档:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/ocr/ocr.idcard.html
     * @param {生成的accessToken}  accessToken
     * @param {识别的证件类型, bankcard :银行卡号; bizlicense:营业执照 OCR 识别; drivinglicense:驾驶证 OCR 识别; :身份证 OCR 识别;comm :小程序的通用印刷体 OCR 识别; driving:程序的行驶证 OCR 识别}  type
     * @param {输入金额值, string}  img_url  要检测的图片 url,传这个则不用传 img 参数。  上传到服务器转成链接图片的识别
     * @param {输入金额值, FormData}  img  form-data 中媒体文件标识,有filename、filelength、content-type等信息,传这个则不用传 img_url。 本地文件识别【按道理来说这个是比较合理的】
     * @return {获取access_token}
     */
    idCardQCR(accessToken, img_url, type = 'idcard') {
        return new Promise((resolve, reject) => {
            wx.request({
                method: 'post',
                url: `https://api.weixin.qq.com/cv/ocr/${type}?type=MODE&img_url=${img_url}&access_token=${accessToken}`,
                success(res) {
                    console.log('识别证件', res)
                    if (res.errMsg === "request:ok") {
                        resolve(res.data)
                    } else {
                        wx.showToast({
                            title: '获取access_token失败!',
                            icon: 'none'
                        })
                    }
                },
                fail(res) {
                    wx.showToast({
                        title: '获取access_token失败!',
                        icon: 'none'
                    })
                    reject(res)
                }
            })
        })
    }

页面调用:

      app.commonModel.common.getAccessToken().then(responce => {
          console.log('页面请求成功', responce)
          app.commonModel.common.idCardQCR(responce.access_token, 'http://3pl.dekuncn.com//upload/2021-12-22/2021122203435670RVNIITYN.jpg','bankcard')
      })

【注意】前端存放appID和AppSecret的风险是,我们借助解除跨域限制的谷歌浏览器【推荐文章:前端浏览器跨域问题】,也同样可以实现其接口调用,这就导致了一个问题就是如果是其他人拿到了这些信息,就会引发问题 Image.png

3、 借助腾讯云AI开放平台实现证件识别【种类多,识别度高】

官网:ai.qq.com/

腾讯云官网:cloud.tencent.com/act

【注意】这里都是后端的工作,所以前端了解一下就可以了。如果要做成跨平台通用方式的QCR识别,需要后端给你识别接口,然后应用于各端

4、 使用小程序云函数进行证件识别

参考文章: 微信小程序-云函数-OCR识别

5、 使用小程序QCR插件进行证件识别

【注意】此插件需要有摄像头的手机设备才可使用 效果为:

ec34e05a4648faf3c45baf47ef3b6f9.png d9dbe7df41705d2b0d8769249dab4b7.png

1、 app.json文件中使用

    "plugins": {
        "ocr-plugin": {
            "version": "3.1.2",
            "provider": "wx4418e3e031e551be"
        }
    }

2、 页面中使用

cardIdentify.wxml 文件

    <!-- 小程序QCR插件 -->
    <headTitle title='小程序QCR插件'>
        <view class="paddingLeftRight16 paddingBtm16 " slot='content'>
            <view class="content-title">
                插件文档:<text data-copyData='{{QCRPluginDoc}}' bindtap="copyAiText" class="hrefCss">{{ QCRPluginDoc }}</text>
            </view>
            
            <view class="content-title">
                通用印刷体QCR,此插件不支持。可以使用云函数开发
            </view>
            <view class="margin-top">
                <ocr-navigator bind:onSuccess="QCRFontIdCard" certificateType="idCard" opposite="{{false}}">
                    <button type="primary" class="marginBtm5">身份证正面识别</button>
                </ocr-navigator>

                <ocr-navigator bind:onSuccess="QCRBackIdCard" certificateType="idCard" opposite="{{true}}">
                    <button type="primary" class="marginBtm5">身份证反面识别</button>
                </ocr-navigator>

                <ocr-navigator bind:onSuccess="QCRBanksuccess" certificateType="bankCard">
                    <button type="primary" class="marginBtm5">银行卡识别</button>
                </ocr-navigator>

                <ocr-navigator bind:onSuccess="QCRDriverSuccess" certificateType="drivingLicense" selectedOptions="{{['plateNum','vehicleType','owner']}}">
                    <button type="primary" class="marginBtm5">行驶证识别</button>
                </ocr-navigator>

                <ocr-navigator bind:onSuccess="QCRDriverLicenseSuccess" certificateType="driverslicense">
                    <button type="primary" class="marginBtm5">驾驶证识别</button>
                </ocr-navigator>

                <ocr-navigator bind:onSuccess="QCRBusinessSuccess" certificateType="businessLicense">
                    <button type="primary" class="marginBtm5">营业执照识别</button>
                </ocr-navigator>

                <ocr-navigator bind:onSuccess="QCRPlatenumSuccess" certificateType="platenum">
                    <button type="primary" class="marginBtm5">车牌识别</button>
                </ocr-navigator>

                <ocr-navigator bind:onSuccess="QCRMenuSuccess" certificateType="menu">
                    <button type="primary" class="marginBtm5">菜单</button>
                </ocr-navigator>

                <!-- <ocr-navigator bind:onSuccess="QCRPrintedFontSuccess" certificateType="print">
                    <button type="primary">通用印刷体QCR</button>
                </ocr-navigator> -->
            </view>
            <view class="margin-top">
                <view class="content-title">
                    注意:
                </view>
                <view class="font-14-thin">
                    识别完图片之后,可以通过该插件回调返回的img_path的路径作为上传路径传给后台
                </view>
            </view>
        </view>
    </headTitle>

cardIdentify.json 文件

{
  "usingComponents": {
    "ocr-navigator": "plugin://ocr-plugin/ocr-navigator"
  },
  "navigationBarTitleText": "证件识别"
}

cardIdentify.js 文件

    /* *****************  小程序QCR插件证件识别  ******************* */
    // 身份证识别--正面调用成功
    QCRFontIdCard(ele) {
        console.log('身份证识别调用成功', ele.detail)
        const idCard = ele.detail
        const address = idCard.address.text
        const birth = idCard.birth.text
        const gender = idCard.gender.text
        const source = idCard.image_source
        const idNumer = idCard.id.text
        const name = idCard.name.text
        const nationality = idCard.nationality.text
        const image_path = idCard.image_path

        const info = `姓名:${name};\n性别:${gender};\n民族:${nationality};\n出生日期:${birth};\n住址:${address};\n身份证号码:${idNumer};\n识别来源:${source}`
        wx.showModal({
            title: '身份证正面识别信息',
            content: info,
            success(res) {
                if (res.confirm) {
                    console.log('用户确认信息无误,调用上传图片接口')
                    // app.commonModel.apis.upLoadImg(image_path).then(resData => {
                    //     console.log('上传识别的图片',resData)
                    // })
                }
            }
        })
    },

    // 身份证识别--背面调用成功
    QCRBackIdCard(ele) {
        console.log('身份证背面识别调用成功', ele.detail)
        const backInfo = ele.detail
        const authority = backInfo.authority.text
        const validDate = backInfo.valid_date.text
        const source = backInfo.image_source
        const backInfoStr = `签发机关:${authority};\n有效期限:${validDate};\n识别来源:${source}`
        wx.showModal({
            title: '身份证背面识别信息',
            content: backInfoStr,
            success(res) {
                if (res.confirm) {
                    console.log('用户确认信息无误,调用上传图片接口')
                    // app.commonModel.apis.upLoadImg(image_path).then(resData => {
                    //     console.log('上传识别的图片',resData)
                    // })
                }
            }
        })
    },

    // 银行卡识别
    QCRBanksuccess(ele) {
        console.log('银行卡号识别', ele.detail)
        const bankInfo = ele.detail
        const bankNumber = bankInfo.number.text
        const source = bankInfo.image_source

        const bankStr = `银行卡号:${bankNumber};\n识别来源:${source}`
        wx.showModal({
            title: '银行卡号识别信息',
            content: bankStr,
            success(res) {
                if (res.confirm) {
                    console.log('用户确认信息无误,调用上传图片接口')
                    // app.commonModel.apis.upLoadImg(image_path).then(resData => {
                    //     console.log('上传识别的图片',resData)
                    // })
                }
            }
        })
    },

    // 行驶证识别
    QCRDriverSuccess(ele) {
        console.log('行驶证识别', ele.detail)
        const driverInfo = ele.detail
        const source = driverInfo.image_source
        const image_path = driverInfo.image_path

        const addr = driverInfo.addr.text
        const check_record = driverInfo.check_record.text
        const engine_num = driverInfo.engine_num.text
        const issue_date = driverInfo.issue_date.text
        const load_quality = driverInfo.load_quality.text
        const model = driverInfo.model.text
        const official_seal = driverInfo.official_seal.text
        const overall_size = driverInfo.overall_size.text
        const owner = driverInfo.owner.text
        const passengers_num = driverInfo.passengers_num.text
        const plate_num = driverInfo.plate_num.text
        const plate_num_b = driverInfo.plate_num_b.text
        const prepare_quality = driverInfo.prepare_quality.text
        const record = driverInfo.record.text
        const register_date = driverInfo.register_date.text
        const remarks = driverInfo.remarks.text
        const total_quality = driverInfo.total_quality.text
        const use_character = driverInfo.use_character.text
        const vehicle_type = driverInfo.vehicle_type.text
        const vin = driverInfo.vin.text

        const driverInfoStr = `正面:\n号牌号码:${plate_num};车辆类型:${vehicle_type};所有人:${owner};住址:${addr};使用性质:${use_character};品牌型号:${model};车辆识别代号:${vin};发动机号码:${engine_num};注册日期:${register_date};发证日期:${issue_date};发证部门:${official_seal};`

        const backDriverInfo = `反面:\n号牌号码:${plate_num_b};档案编号:${record};核定载人数:${passengers_num};总质量:${total_quality};整备质量:${prepare_quality};核定载质量:${load_quality};外廓尺寸:${overall_size};准牵引总质量:  ;备注:${remarks};检验有效期:${check_record};`
        // const bankStr = `银行卡号:${bankNumber};\n识别来源:${source}`
        wx.showModal({
            title: '行驶证别信息',
            content: driverInfoStr + backDriverInfo
        })
    },

    // 驾驶证识别
    QCRDriverLicenseSuccess(ele) {
        console.log('驾驶证识别', ele.detail)
        const driverInfo = ele.detail
        const source = driverInfo.image_source
        const image_path = driverInfo.image_path

        const address = driverInfo.address.text
        const birth_date = driverInfo.birth_date.text
        const car_class = driverInfo.car_class.text
        const file_no = driverInfo.file_no.text
        const id_num = driverInfo.id_num.text
        const issue_date = driverInfo.issue_date.text
        const name = driverInfo.name.text
        const nationality = driverInfo.nationality.text
        const official_seal = driverInfo.official_seal.text
        const remarks = driverInfo.remarks.text
        const sex = driverInfo.sex.text
        const valid_from = driverInfo.valid_from.text
        const valid_to = driverInfo.valid_to.text


        const driverInfoStr = `正面:\n姓名:${name};性别:${sex};国籍:${nationality};住址:${address};出生日期:${birth_date};初次领证日期:${issue_date};准假车型:${car_class};有效期限:${valid_from}至${valid_to};发证部门:${official_seal};\n反面:\n档案编号:${file_no};证号:${id_num};备注:${remarks};`
        wx.showModal({
            title: '驾驶证识别信息',
            content: driverInfoStr
        })
    },

    // 营业执照识别
    QCRBusinessSuccess(ele) {
        console.log('营业执照识别', ele)
    },

    // 车牌识别
    QCRPlatenumSuccess(ele) {
        console.log('车牌识别', ele)
        const carNo = ele.number.text
        console.log('识别的车牌号为', carNo)
    },

    // 菜单识别
    QCRMenuSuccess(ele) {
        console.log('菜单识别', ele)
        const menuItem = ele.detail
        console.log('菜单识别内容', menuItem)
        const { image_path , image_source , items } = menuItem

        let str = ''
        if(items.length){
            str = items.map(ele=>`${ele.menu_name}:${ele.menu_price}${ele.menu_memo}`).join('\n')
            wx.showModal({
                title: '菜单识别信息',
                content: str
            })
        }else{
            wx.showToast({
              title: '无菜单信息',
              icon:'none'
            })
        }
    },

    // 通用印刷体QCR
    QCRPrintedFontSuccess(ele) {
        console.log('通用印刷体QCR', ele)
    },


    /* *****************  小程序QCR插件证件识别  ******************* */