1. 程式人生 > >微信識別圖片功能實現(以讀取銀行卡為例)

微信識別圖片功能實現(以讀取銀行卡為例)

支付 ref gb2312 sta mil img 身份證識別 manager his

一,需求講解

技術分享

技術分享

如圖所示,掃描圖片的時候,實現銀行卡號和銀行名稱自動回填。

二,代碼

2.1,html頁面

 1             <input type="file" name="upload" style="display:none;" onchange="ocrScan(this);" id="upload" accept="image/*"/>
 2 
 3 
 4  <li class="item-list">
 5                     <span class="name" >銀行卡號</span>
 6                     <img class
="fr bank-img" onclick="ocrScanProxy();" src="${rc.contextPath}/js/css/images/[email protected]"/> 7 <input class="fr bank-number" id="accountNoShow" name="accountNoShow" value="${orderParam.accountNoShow?default(‘‘)}" placeholder="請填寫卡號,掃描可自動填充" /> 8 </li> 9
10 function ocrScanProxy(){ 11 $("#upload").click(); 12 } 13 14 function ocrScan(imgFile){ 15 var file = imgFile.files[0];//文件對象 16 var name = file.name;//圖片名 17 var url = ‘${rc.contextPath}/wxInComing.htm?method=ocrScan‘; 18 $.ajaxFileUpload({ 19 url: url,
20 secureuri:false, 21 type: ‘POST‘, 22 fileElementId:"upload", 23 dataType: ‘json‘, 24 success: function (data, status) //服務器成功響應處理函數 25 { 26 var index = data.indexOf(‘{‘); 27 data= data.substring(index, data.length); 28 var obj = eval(‘(‘ + data + ‘)‘); 29 if ("000" == obj.code) { 30 $("#accountNo").val(obj.data.cardno.replace(/\s/g,‘‘)); 31 $("#accountNoShow").val(obj.data.cardno); 32 var bankName = obj.data.bankname; 33 if(bankName.indexOf(‘(‘) > -1) { 34 bankName = bankName.substring(0,bankName.indexOf(‘(‘)) 35 } 36 $("#bankNameShow").text(bankName); 37 $("#bankName").val(bankName); 38 } else { 39 alert(obj.desc); 40 } 41 }, 42 error: function (data, status, e)//服務器響應失敗處理函數 43 { 44 alert(e); 45 } 46 }); 47 }

以上用的是ajaxupload異步提交,解決請求頭的問題。一旦發送請求在到達方法前已近把post裏面的圖片放到這個目錄下面去了,

D:\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp5\work\Catalina\localhost\項目名,換句話就是說在發送請求之前,到達方法之前就會把這張圖片放到這個目錄下,一旦請求結束,這張照片就會被刪除。

技術分享

上面的圖片中的post轉的就是這張圖片的二進制的內容。

後續對HttpServletRequest 和response進行細致的了解,https://www.cnblogs.com/xdp-gacl/p/3798347.html這個博文不錯

2.2,ocrScan類

 1 public void ocrScan(HttpServletRequest request, HttpServletResponse response) {
 2         Map<String, Object> result = new HashMap<String, Object>();
 3         try {
 4             MultipartHttpServletRequest multipartRequest = null;
 5             multipartRequest = (MultipartHttpServletRequest) request;
 6             MultipartFile inputFile = multipartRequest.getFile("upload");
 7             if(null == inputFile){
 8                 result.put("code", "002");
 9                 result.put("desc", "圖片不能為空");
10                 super.toJson(result, response);
11                 return;
12             }
13             Map<String, Object> bankCardRecognize = ocrService.bankCardRecognize(inputFile);
14             if("0".equals(bankCardRecognize.get("Error"))){
15                 result.put("code", "000");
16                 result.put("desc", "sucesss");
17                 result.put("data", bankCardRecognize.get("Result"));
18                 super.toJson(result, response);
19                 return;
20             } else {
21                 result.put("code", bankCardRecognize.get("Error"));
22                 result.put("desc", bankCardRecognize.get("Details"));
23                 super.toJson(result, response);
24                 return;
25             }
26         } catch(Exception e) {
27             logger.error("com.bill99.query.controller.WXinComingController.ocrScan()發生異常,異常信息為:",e);
28             result.put("code", "003");
29             result.put("desc", "ocr識別異常");
30             super.toJson(result, response);
31             return;
32         }
33     }

到這之後可以得到inputfile的參數

MultipartFile inputFile = multipartRequest.getFile("upload");

--這是根據id來獲取的異步請求的數據,主要有圖片的名稱,地址,大小,還有input為file圖片格式的name

它的結果為
name=timg.jpg, StoreLocation=D:\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp5\work\Catalina\localhost\weixin\upload__6daf3b82_15fa64c1e0f__8000_00000010.tmp, size=103086bytes, isFormField=false, FieldName=upload

在這只不過是圖片的一個路徑而已,不是二進制的文件,調用的類回去這裏面去讀取數據的。

現在把這個file傳給ocr的識別系統
Map<String, Object> bankCardRecognize = ocrService.bankCardRecognize(inputFile);

2.3,OcrService接口

1 /**
2      * 銀行卡識別
3      * 
4      * @param imageFile
5      * @return
6      */
7     Map<String, Object> bankCardRecognize(MultipartFile imageFile);

2.4,OcrServiceImpl實現類

1 @Override
2     public Map<String, Object> bankCardRecognize(MultipartFile imageFile) {
3         return ocrServer.pictureRecognition("BankCard", imageFile);
4     }

2.5,ocr服務接口調用類OcrServer

 1 package com.bill99.coe.ocr.client;
 2 
 3 import java.io.FileInputStream;
 4 import java.io.IOException;
 5 import java.util.HashMap;
 6 import java.util.Map;
 7 
 8 import org.apache.commons.codec.binary.Base64;
 9 import org.slf4j.Logger;
10 import org.slf4j.LoggerFactory;
11 import org.springframework.web.multipart.MultipartFile;
12 
13 import com.bill99.boss.domain.service.CpConfigService;
14 import com.bill99.boss.utils.util.JsonUtils;
15 import com.bill99.coe.ocr.utils.HttpUtil;
16 
17 /**
18  * ocr服務接口調用
19  * 
20  * @author liangjian.sun
21  *
22  */
23 public class OcrServer {
24     /**
25      * 日誌
26      */
27     private static Logger logger = LoggerFactory.getLogger(OcrServer.class);
28     
29     /**
30      * 配置參數服務
31      */
32     private CpConfigService cpConfigService = null;
33     
34     /**
35      * 圖片識別
36      * @param recotype
37      *         要識別的證件類型
38      * @param imageFile
39      *         要識別的證件文件
40      * @return Map<String, Object>
41      *         識別結果
42      */
43     public Map<String, Object> pictureRecognition(String recotype, MultipartFile imageFile) {
44         String result = null;
45         // 文件輸入流
46         FileInputStream fs = null;
47         try {
48             String configValue = cpConfigService.getValueByConfigKey("ocr_server_config", "{‘uri‘:‘http://cloud.exocr.com/recognize‘,‘username‘:‘test‘,‘password‘:‘test‘}");
49             Map<String, String> configMap = JsonUtils.json2Map2(configValue);
50             String postUrl = configMap.get("uri"); // 服務地址
51             Map<String, String> postParam = new HashMap<String, String>(10);
52             postParam.put("username", configMap.get("username")); // 用戶名, 公有雲測試可使用’test’
53             postParam.put("password", configMap.get("password")); // 密碼,公有雲測試可使用 ’test’
54             postParam.put("recotype", recotype); // BankCard
55             postParam.put("encoding", "utf-8"); // 返回結果的文字編碼方式,取值包括:utf-8, 默認值 gb2312   
56             postParam.put("head_portrait", "0"); // 是否返回頭像(base64格式),只對身份證識別有效,取值範圍:0,默認,不返回頭像    1,則返回身份證的頭像照片 
57             postParam.put("crop_image", "0"); // 是否返回切邊(base64格式),取值:0,    默認,不返回切邊圖    1,    返回切邊圖
58             postParam.put("b64", "1"); // 輸入圖片是否為base64格式,取值:0,    默認,二進制格式   1,    base64格式
59             // base64編碼圖像
60             String base64 = new String(Base64.encodeBase64(imageFile.getBytes()));
61             postParam.put("image", base64); // 待識別的圖像,可以是二進制也可以是base64格式
62             result = HttpUtil.postUrlAsString(postUrl, postParam, null, "utf-8");
63             logger.info("OCR識別結果{}", result);
64         } catch (Exception e) {
65             logger.error("OCR識別異常:", e);
66             StringBuilder sb = new StringBuilder();
67             sb.append("{‘Error‘:‘99‘,‘Details‘:‘OCR識別異常:");
68             sb.append(e.getMessage()).append("‘}");
69             result = sb.toString();
70         } finally {
71             if (null != fs) {
72                 try {
73                     fs.close();
74                 } catch (IOException e) {
75                     logger.error("File input stream close exception:", e);
76                 }
77             }
78         }
79         
80         try {
81             return JsonUtils.json2Map(result);
82         } catch (Exception e) {
83             logger.error("json to map exception:", e);
84         }
85         
86         return null;
87     }
88 
89     public void setCpConfigService(CpConfigService cpConfigService) {
90         this.cpConfigService = cpConfigService;
91     }
92 
93 }

來獲取這個url的接口
String configValue = cpConfigService.getValueByConfigKey("ocr_server_config", "{‘uri‘:‘http://cloud.exocr.com/recognize‘,‘username‘:‘test‘,‘password‘:‘test‘}");
把所有的參數封裝到postParam參數中來{b64=1, username=test, head_portrait=0, recotype=BankCard, encoding=utf-8, image=/9j/4AA........}
postParam.put("image", base64); // 待識別的圖像,可以是二進制也可以是base64格式

2.6,HTTP工具類,HttpUtil

  1 package com.bill99.coe.ocr.utils;
  2 
  3 import java.io.UnsupportedEncodingException;
  4 import java.util.ArrayList;
  5 import java.util.List;
  6 import java.util.Map;
  7 
  8 import org.apache.commons.lang.StringUtils;
  9 import org.apache.http.Header;
 10 import org.apache.http.HttpResponse;
 11 import org.apache.http.HttpStatus;
 12 import org.apache.http.NameValuePair;
 13 import org.apache.http.client.HttpClient;
 14 import org.apache.http.client.entity.UrlEncodedFormEntity;
 15 import org.apache.http.client.methods.HttpPost;
 16 import org.apache.http.client.methods.HttpUriRequest;
 17 import org.apache.http.impl.client.DefaultHttpClient;
 18 import org.apache.http.message.BasicNameValuePair;
 19 import org.apache.http.params.CoreConnectionPNames;
 20 import org.apache.http.util.EntityUtils;
 21 import org.slf4j.Logger;
 22 import org.slf4j.LoggerFactory;
 23   
 24 /** 
 25  * HTTP工具類. 
 26  *  
 27  * @author David.Huang 
 28  */  
 29 public class HttpUtil {  
 30   
 31     private static Logger logger = LoggerFactory.getLogger(HttpUtil.class);  
 32   
 33     /**
 34      * 默認編碼方式 -UTF8  
 35      */
 36     private static final String DEFAULT_ENCODE = "utf-8";  
 37       
 38     /** 
 39      * POST請求, 結果以字符串形式返回. 
 40      *  
 41      * @param url 
 42      *            請求地址 
 43      * @param params 
 44      *            請求參數 
 45      * @param reqHeader 
 46      *            請求頭內容 
 47      * @param encode 
 48      *            編碼方式 
 49      * @return 內容字符串 
 50      * @throws Exception 
 51      */  
 52     public static String postUrlAsString(String url,  
 53             Map<String, String> params, Map<String, String> reqHeader,  
 54             String encode) throws Exception {  
 55         // 開始時間  
 56         long t1 = System.currentTimeMillis();  
 57         // 獲得HttpPost對象  
 58         HttpPost httpPost = getHttpPost(url, params, encode);  
 59         // 發送請求  
 60         String result = executeHttpRequest(httpPost, reqHeader, encode);  
 61         // 結束時間  
 62         long t2 = System.currentTimeMillis();  
 63         // 調試信息  
 64         logger.debug("url:" + url);  
 65         logger.debug("params:" + params.toString());  
 66         logger.debug("reqHeader:" + reqHeader);  
 67         logger.debug("encode:" + encode);  
 68         logger.debug("result:" + result);  
 69         logger.debug("consume time:" + ((t2 - t1)));  
 70         // 返回結果  
 71         return result;  
 72     }  
 73       
 74     /** 
 75      * 獲得HttpPost對象 
 76      *  
 77      * @param url 
 78      *            請求地址 
 79      * @param params 
 80      *            請求參數 
 81      * @param encode 
 82      *            編碼方式 
 83      * @return HttpPost對象 
 84      * @throws UnsupportedEncodingException 
 85      */  
 86     private static HttpPost getHttpPost(String url, Map<String, String> params,  
 87             String encode) throws UnsupportedEncodingException {  
 88         HttpPost httpPost = new HttpPost(url);  
 89         if (params != null) {  
 90             List<NameValuePair> form = new ArrayList<NameValuePair>();  
 91             for (String name : params.keySet()) {  
 92                 form.add(new BasicNameValuePair(name, params.get(name)));  
 93             }
 94             
 95             UrlEncodedFormEntity entity = new UrlEncodedFormEntity(form,  
 96                     encode);  
 97             httpPost.setEntity(entity);  
 98         }
 99         
100         return httpPost;  
101     }  
102   
103     /** 
104      * 執行HTTP請求 
105      *  
106      * @param request 
107      *            請求對象 
108      * @param reqHeader 
109      *            請求頭信息 
110      * @return 內容字符串 
111      */  
112     private static String executeHttpRequest(HttpUriRequest request,  
113             Map<String, String> reqHeader, String encode) throws Exception {  
114         HttpClient client = null;  
115         String result = null;  
116         try {  
117             // 創建HttpClient對象  
118             client = new DefaultHttpClient();  
119             // 設置連接超時時間  
120             client.getParams().setParameter(  
121                     CoreConnectionPNames.CONNECTION_TIMEOUT, 60);  
122             // 設置Socket超時時間  
123             client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT,  
124                     36600);  
125             // 設置請求頭信息  
126             if (reqHeader != null) {  
127                 for (String name : reqHeader.keySet()) {  
128                     request.addHeader(name, reqHeader.get(name));  
129                 }  
130             }  
131             // 獲得返回結果  
132             HttpResponse response = client.execute(request);  
133             // 如果成功  
134             if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { 
135                 encode = StringUtils.isNotEmpty(encode) ? encode : DEFAULT_ENCODE;
136                 result = EntityUtils.toString(response.getEntity(), encode);  
137             } else {  
138                 StringBuffer errorMsg = new StringBuffer();  
139                 errorMsg.append("httpStatus:");  
140                 errorMsg.append(response.getStatusLine().getStatusCode());  
141                 errorMsg.append(response.getStatusLine().getReasonPhrase());  
142                 errorMsg.append(", Header: ");  
143                 Header[] headers = response.getAllHeaders();  
144                 for (Header header : headers) {  
145                     errorMsg.append(header.getName());  
146                     errorMsg.append(":");  
147                     errorMsg.append(header.getValue());  
148                 }  
149                 logger.error("HttpResonse Error:" + errorMsg);  
150                 result = "{‘Error‘:‘98‘,‘Details‘:‘" + errorMsg.toString() + "‘}";
151             }  
152         } catch (Exception e) {  
153             logger.error("http連接異常", e);  
154             throw new Exception("http連接異常");  
155         } finally {  
156             try {  
157                 client.getConnectionManager().shutdown();  
158             } catch (Exception e) {  
159                 logger.error("finally HttpClient shutdown error", e);  
160             }  
161         }  
162         return result;  
163     }  
164 }

仿照瀏覽器把參數全部分裝到httpPost請求當中來,最主要的就是url路徑,參數,和編碼格式httppost的用法(NameValuePair(簡單名稱值對節點類型))
HttpPost httpPost = getHttpPost(url, params, encode);
通過httpclient來把數據傳到orc的服務器並返回結果。httpclient的講解
String result = executeHttpRequest(httpPost, reqHeader, encode);

。。。。。

返回的結果{Error=0, Details=識別正確, Result={bankname=中銀通支付(480800010000), cardname=安徽合肥通卡, cardtype=預付費卡, cardno=9210 0001 0000 1595 143, expmonth=0, expyear=0}}

2.7,識別返回的json格式文檔

1 銀行卡識別結果JSON數據定義:
2         "bankname"   --------------銀行名稱
3     "cardname"  --------------卡名
4     "cardtype"  --------------卡類型
5     “cardno”    -------------卡號
6     “expmonth” ---------------有效期截止月份
7     “expyear”  ----------------有效期截止年份
8     "cropped_image" ---------------切割圖

身份證識別,行駛證識別,駕駛證識別,營業執照識別大同小異,主要是返回結果不一樣。具體請見微信圖片身份證識別,行駛證識別,駕駛證識別,營業執照識

微信識別圖片功能實現(以讀取銀行卡為例)