银行卡信息精准识别-智能快速绑卡

684 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情

1. 前言

在AI人工智能的潮流下,出现了很多方便人们生活的产品:人脸识别技术-完成人脸开锁,人脸核身;车牌识别-完成停车场无人计费系统设计;自动驾驶-辅助车主行车,自动泊车等等,还有很多相关的应用。

这篇文章就是利用华为云提供的银行卡信息识别接口来提取识别银行卡详细信息,这个接口是文字识别接口中的一个,银行卡信息识别主要是应用在各种购物app里绑卡、保险在线理赔填卡号、社交软件绑卡、证券软件绑卡等等很多地方,以前都是人工输入卡号,非常不方便,有了AI识别功能,可以提前将银行卡图片保存在手机里,也可以选择现场拍摄,这样软件通过图片快速识别出当前银行卡的类别、所属银行、卡号等信息完成自动填充,极大的方便用户体验。

image-20220211110324975

2. 文字识别云服务

2.1 开通文字识别服务功能

地址: console.huaweicloud.com/ocr/?region…

image-20220211111123655

文字识别服务接口支持API方式调用,支持按需计费,每个用户每月有1000次的免费调用额度,前期的体验调试比较方便。

接口的计费使用说明: support.huaweicloud.com/productdesc…

image-20220211111348612

2.2 API接口使用介绍

帮助文档地址: support.huaweicloud.com/api-ocr/ocr…

接口识别银行卡上的关键文字信息后,是以json格式返回识别的结果,根据说明解析就能拿到信息。

接口格式:

 URL请求格式:POST https://{endpoint}/v2/{project_id}/ocr/bankcard
 ​
 endpoint 指定承载REST服务端点的服务器域名或IP,不同服务不同区域的endpoint不同,可以从终端节点中获取。
 例如,OCR服务在"华北-北京四"区域的"endpoint""ocr.cn-north-4.myhuaweicloud.com"。
 ​
 project_id是项目ID,可以从这里 https://support.huaweicloud.com/api-ocr/ocr_03_0130.html 获取。
 ​
 ​
 完整请求示例: 
 https://ocr.cn-north-4.myhuaweicloud.com/v2/0e5957be8a00f53c2fa7c0045e4d8fbf/ocr/bankcard
 ​
 请求头:
 {
  "X-Auth-Token": "******",
  "Content-Type": "application/json;charset=UTF-8"
 }
 ​
 X-Auth-Token参考在这里获取:https://support.huaweicloud.com/api-ocr/ocr_03_0005.html
 ​
 请求体里包含了图片的bash编码数据
 {
  "image": ..............
 }
 ​
 ​
 识别后响应的结果:
 {
  "result": {
   "bank_name": "中国建设银行",
   "card_number": "6217003860002354304",
   "issue_date": "",
   "expiry_date": "09/22",
   "type": "借记卡",
   "confidence": {
    "bank_name": 0.9608,
    "card_number": 0.9793,
    "issue_date": 0,
    "expiry_date": 0.8646,
    "type": 0
   }
  }
 }
 ​
 响应结果里字段含义解释:
 ​
 bank_name  发卡行。
 ​
 card_number 银行卡号。
 ​
 issue_date 有效期开始日期。
 ​
 expiry_date 有效期截止日期。
 ​
 type 银行卡类别,如:借记卡,信用卡,准贷记卡,预付费卡。

2.3 在线调试

在线调试地址: apiexplorer.developer.huaweicloud.com/apiexplorer…

先通过调试接口体验之后,再编写代码可以少走一些弯路,很多参数都比较清楚了。

image-20220211112958274

将图片的base64编码贴到 image字段里,点击调试即可查看结果。

3. 示例代码

代码采用QT编写,主要是就是HTTP请求,获取结果,解析结果,API接口不依赖语言,任何语言使用都是一样的流程。

image-20220211115946809

image-20220211120010999

3.2 发起请求,获取银行卡信息

 //获取银行卡信息
 void  Widget::getCardInfo(QString file)
 {
     function_select=1;
     QString requestUrl;
     QNetworkRequest request;
 ​
     //存放图片BASE64编码
     QString imgData;
 ​
     //设置请求地址
     QUrl url;
 ​
     //人脸搜索请求地址
     requestUrl = QString("https://ocr.%1.myhuaweicloud.com/v2/%2/ocr/bankcard")
             .arg(SERVER_ID)
             .arg(PROJECT_ID);
 ​
     //设置数据提交格式
     request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));
 ​
     //将图片进行Base64编码
     imgData = QString(toBase64(QImage(file))); //编码后的图片大小不超过2M
     //设置token
     request.setRawHeader("X-Auth-Token",Token);
 ​
     //构造请求
     url.setUrl(requestUrl);
     request.setUrl(url);
 ​
     QString post_param=QString
                ("{"
                  ""image": "%1""
                 "}").arg(imgData);
 ​
     //发送请求
     manager->post(request, post_param.toUtf8());
 }

3.3 获取token

 /*
 功能: 获取token
 */
 void Widget::GetToken()
 {
     //表示获取token
     function_select=3;
 ​
     QString requestUrl;
     QNetworkRequest request;
 ​
     //设置请求地址
     QUrl url;
 ​
     //获取token请求地址
     requestUrl = QString("https://iam.%1.myhuaweicloud.com/v3/auth/tokens")
                  .arg(SERVER_ID);
 ​
     //自己创建的TCP服务器,测试用
     //requestUrl="http://10.0.0.6:8080";
 ​
     //设置数据提交格式
     request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json;charset=UTF-8"));
 ​
     //构造请求
     url.setUrl(requestUrl);
 ​
     request.setUrl(url);
 ​
     QString text =QString("{"auth":{"identity":{"methods":["password"],"password":"
     "{"user":{"domain": {"
     ""name":"%1"},"name": "%2","password": "%3"}}},"
     ""scope":{"project":{"name":"%4"}}}}")
             .arg(MAIN_USER)
             .arg(IAM_USER)
             .arg(IAM_PASSWORD)
             .arg(SERVER_ID);
 ​
     //发送请求
     manager->post(request, text.toUtf8());
 }

3.4 解析结果

 //解析反馈结果
 void Widget::replyFinished(QNetworkReply *reply)
 {
     QString displayInfo="";
     int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
 ​
     //读取所有数据
     QByteArray replyData = reply->readAll();
 ​
     qDebug()<<"状态码:"<<statusCode;
     qDebug()<<"反馈的数据:"<<QString(replyData);
 ​
     //更新token
     if(function_select==3)
     {
         displayInfo="token 更新失败.";
         //读取HTTP响应头的数据
         QList<QNetworkReply::RawHeaderPair> RawHeader=reply->rawHeaderPairs();
         qDebug()<<"HTTP响应头数量:"<<RawHeader.size();
         for(int i=0;i<RawHeader.size();i++)
         {
             QString first=RawHeader.at(i).first;
             QString second=RawHeader.at(i).second;
             if(first=="X-Subject-Token")
             {
                 Token=second.toUtf8();
                 displayInfo="token 更新成功.";
 ​
                 //保存到文件
                 SaveDataToFile(Token);
                 break;
             }
         }
         QMessageBox::information(this,"提示",displayInfo,QMessageBox::Ok,QMessageBox::Ok);
         return;
     }
 ​
     //判断状态码
     if(200 != statusCode)
     {
         //解析数据
         QJsonParseError json_error;
         QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error);
         if(json_error.error == QJsonParseError::NoError)
         {
             //判断是否是对象,然后开始解析数据
             if(document.isObject())
             {
                 QString error_str="";
                 QJsonObject obj = document.object();
                 QString error_code;
                 //解析错误代码
                 if(obj.contains("error_code"))
                 {
                     error_code=obj.take("error_code").toString();
                     error_str+="错误代码:";
                     error_str+=error_code;
                     error_str+="\n";
                 }
                 if(obj.contains("error_msg"))
                 {
                     error_str+="错误消息:";
                     error_str+=obj.take("error_msg").toString();
                     error_str+="\n";
                 }
 ​
                 //显示错误代码
                 QMessageBox::information(this,"提示",error_str,QMessageBox::Ok,QMessageBox::Ok);
             }
          }
         return;
     }
 ​
     //结果返回
     if(function_select==1)
     {
         //解析数据
         QJsonParseError json_error;
         QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error);
         if(json_error.error == QJsonParseError::NoError)
         {
             //判断是否是对象,然后开始解析数据
             if(document.isObject())
             {
                 QJsonObject obj = document.object();
                 QString error_code;
                 //解析
                 if(obj.contains("result"))
                 {
                     QJsonObject obj1=obj.take("result").toObject();
 ​
                     QString bank_name;
                     QString card_number;
                     QString type;
 ​
                     QString text;
                     if(obj1.contains("bank_name"))
                     {
                         bank_name=obj1.take("bank_name").toString();
                     }
                     if(obj1.contains("card_number"))
                     {
                         card_number=obj1.take("card_number").toString();
                     }
                     if(obj1.contains("type"))
                     {
                         type=obj1.take("type").toString();
                     }
 ​
 ​
                     text="发卡行:"+bank_name+"\n";
                     text+="卡号:"+card_number+"\n";
                     text+="卡类型:"+type+"\n";
 ​
                     ui->plainTextEdit->setPlainText(text);
                 }
             }
         }
     }
 }