微信識別圖片功能實現(以讀取銀行卡為例)
一,需求講解
如圖所示,掃描圖片的時候,實現銀行卡號和銀行名稱自動回填。
二,代碼
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> 910 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" ---------------切割圖
身份證識別,行駛證識別,駕駛證識別,營業執照識別大同小異,主要是返回結果不一樣。具體請見微信圖片身份證識別,行駛證識別,駕駛證識別,營業執照識
微信識別圖片功能實現(以讀取銀行卡為例)