通過調用API在JavaWeb項目中實現證件識別


本文詳細介紹自己如何在JavaWeb項目中通過調用API實現證件識別。

一,Face++使用簡介

二,兩種方式(圖片URL與本地上傳)實現證件識別

 

一,Face++使用簡介

Face++曠視人工智能開放平台,核心技術有人臉識別,人體識別,文字識別以及圖像識別。具體詳情可查看官方網站

首先需要在官方網站上注冊,然后在API應用管理創建API Key,便可得到API Key和API Secret。兩者是之后調用API的必要請求參數。

具體操作方式也可查看API文檔

 

        
 

API調用原理:使用者向服務器發起HTTP請求,並加上合適的參數,服務器將會對請求進行處理,得到結果將會返回給使用者。

API調用鑒權:帳號下每創建一個應用程序會生成一組對應的API Key和API Secret,用於識別用戶是否有權限調用API,所有的API調用必須提供對應的一組API Key和API Secret。

API調用參數:調用每個API需要根據需求傳輸不同的參數,身份證識別需要的必須參數有API的URL,API Key,API Secret,image_url或image_file或image_base64以及可選參數legality。

API調用提示:為了避免因網絡問題而造成的阻塞,建議將API調用放進異步線程里執行。

 

二,兩種方式(圖片URL與本地上傳)實現證件識別

不管是通過URL方式還是通過本地上傳,調用API之前首先需要將圖片轉為字節型數組byte[]。官方給的案例只介紹了通過本地上傳,我在其基礎上添加了一個函數 'getBytesFromInputStream'實現將輸入流轉為字節型數組,代碼如下。

  1 package com.aiit.util;
  2 
  3 import java.io.ByteArrayOutputStream;
  4 import java.io.DataOutputStream;
  5 import java.io.File;
  6 import java.io.FileInputStream;
  7 import java.io.IOException;
  8 import java.io.InputStream;
  9 import java.net.HttpURLConnection;
 10 import java.net.URL;
 11 import java.net.URLEncoder;
 12 import java.util.HashMap;
 13 import java.util.Iterator;
 14 import java.util.Map;
 15 import java.util.Random;
 16 
 17 import javax.net.ssl.SSLException;
 18 
 19 /**
 20  * 身份證識別
 21  * @ClassName:CertificateRecognition.java
 22  */
 23 public class CertificateRecognition {
 24     
 25     
 26     private final static int CONNECT_TIME_OUT = 30000;
 27     private final static int READ_OUT_TIME = 50000;
 28     private static String boundaryString = getBoundary();
 29     
 30     //url參數為身份證識別API的URL,map參數存放的是api_key、api_secret等值,fileMap參數存放的是圖片字節型數組
 31     public static byte[] post(String url, HashMap<String, String> map, HashMap<String, byte[]> fileMap) throws Exception {
 32         HttpURLConnection conne;
 33         URL url1 = new URL(url);
 34         conne = (HttpURLConnection) url1.openConnection();
 35         conne.setDoOutput(true);
 36         conne.setUseCaches(false);
 37         conne.setRequestMethod("POST");
 38         conne.setConnectTimeout(CONNECT_TIME_OUT);
 39         conne.setReadTimeout(READ_OUT_TIME);
 40         conne.setRequestProperty("accept", "*/*");
 41         conne.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundaryString);
 42         conne.setRequestProperty("connection", "Keep-Alive");
 43         conne.setRequestProperty("user-agent", "Mozilla/4.0 (compatible;MSIE 6.0;Windows NT 5.1;SV1)");
 44         DataOutputStream obos = new DataOutputStream(conne.getOutputStream());
 45         Iterator iter = map.entrySet().iterator();
 46         while(iter.hasNext()){
 47             Map.Entry<String, String> entry = (Map.Entry) iter.next();
 48             String key = entry.getKey();
 49             String value = entry.getValue();
 50             obos.writeBytes("--" + boundaryString + "\r\n");
 51             obos.writeBytes("Content-Disposition: form-data; name=\"" + key + "\"\r\n");
 52             obos.writeBytes("\r\n");
 53             obos.writeBytes(value + "\r\n");
 54         }
 55         if(fileMap != null && fileMap.size() > 0){
 56             Iterator fileIter = fileMap.entrySet().iterator();
 57             while(fileIter.hasNext()){
 58                 Map.Entry<String, byte[]> fileEntry = (Map.Entry<String, byte[]>) fileIter.next();
 59                 obos.writeBytes("--" + boundaryString + "\r\n");
 60                 obos.writeBytes("Content-Disposition: form-data; name=\"" + fileEntry.getKey() + "\"; filename=\"" + encode(" ") + "\"\r\n");
 61                 obos.writeBytes("\r\n");
 62                 obos.write(fileEntry.getValue());
 63                 obos.writeBytes("\r\n");
 64             }
 65         }
 66         obos.writeBytes("--" + boundaryString + "--" + "\r\n");
 67         obos.writeBytes("\r\n");
 68         obos.flush();
 69         obos.close();
 70         InputStream ins = null;
 71         int code = conne.getResponseCode();
 72         try{
 73             if(code == 200){
 74                 ins = conne.getInputStream();
 75             }else{
 76                 ins = conne.getErrorStream();
 77             }
 78         }catch (SSLException e){
 79             e.printStackTrace();
 80             return new byte[0];
 81         }
 82         ByteArrayOutputStream baos = new ByteArrayOutputStream();
 83         byte[] buff = new byte[4096];
 84         int len;
 85         while((len = ins.read(buff)) != -1){
 86             baos.write(buff, 0, len);
 87         }
 88         byte[] bytes = baos.toByteArray();
 89         ins.close();
 90         return bytes;
 91     }
 92     
 93     private static String getBoundary() {
 94         StringBuilder sb = new StringBuilder();
 95         Random random = new Random();
 96         for(int i = 0; i < 32; ++i) {
 97             sb.append("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-".charAt(random.nextInt("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_".length())));
 98         }
 99         return sb.toString();
100     }
101     
102     //設置字符編碼格式為UTF-8
103     private static String encode(String value) throws Exception{
104         return URLEncoder.encode(value, "UTF-8");
105     }
106     
107     //將二進制文件轉為字節型數組
108     public static byte[] getBytesFromFile(File f) {
109         if (f == null) {
110             return null;
111         }
112         try {
113             FileInputStream stream = new FileInputStream(f);
114             ByteArrayOutputStream out = new ByteArrayOutputStream(1000);
115             byte[] b = new byte[1000];
116             int n;
117             while ((n = stream.read(b)) != -1)
118                 out.write(b, 0, n);
119             stream.close();
120             out.close();
121             return out.toByteArray();
122         } catch (IOException e) {
123         }
124         return null;
125     }
126     
127     //將輸入流轉為字節型數組
128     public static  byte[] getBytesFromInputStream(InputStream inputStream) throws IOException {    
129         byte[] buffer = new byte[1024];    
130         int len = 0;    
131         ByteArrayOutputStream bos = new ByteArrayOutputStream();    
132         while((len = inputStream.read(buffer)) != -1) {    
133             bos.write(buffer, 0, len);    
134         }    
135         bos.close();    
136         return bos.toByteArray();    
137     }
138 
139 }

 

 

 

①通過URL方式

當輸入圖片URL,點擊檢測按鈕,觸發js的click事件,首先根據URL完成修改img標簽的背景圖片,並將其傳給 'readPhoto1' 函數。該函數將URL通過AJAX異步請求傳至Controller層,Controller層通過URL首先建立網絡連接得到輸入流,輸入流通過上述代碼轉為字節型數組,並put至HashMap中作為參數之一。另外兩個參數已經是規定好的,這時再調用post函數,得到返回值轉為JSON格式返回至 'readPhoto1' 函數,該函數再取值通過id賦值給相應的標簽。參考代碼如下。

1 $("#bg-model4_button2").click(function(){
2  var photoURL = document.getElementById("bg-model4_input").value;
3  document.getElementById('bg-model4_img').src = photoURL;
4  readPhoto1(photoURL);
5 });

 

 1 /*通過URL讀取圖片*/
 2 function readPhoto1(photoURL){
 3     $.post("readPhotoInfo1.do",{photoURL},function(data){
 4        document.getElementById("name").innerHTML = data.cards[0].name;
 5        document.getElementById("sex").innerHTML = data.cards[0].gender;
 6        document.getElementById("race").innerHTML = data.cards[0].race;
 7        document.getElementById("birthday").innerHTML = data.cards[0].birthday;
 8        document.getElementById("address").innerHTML = data.cards[0].address;
 9        document.getElementById("idcard_num").innerHTML = data.cards[0].id_card_number;
10        if(data.cards[0].side == "front"){
11             document.getElementById("admin_side").innerHTML = "人像面";
12        }else{
13              document.getElementById("admin_side").innerHTML = "國徽面";
14        }
15        document.getElementById("admin_time_used").innerHTML = data.time_used + "ms";
16     },"json");
17 }

 

 1 private String photoInfo;   //身份證信息
 2     
 3 //根據圖片URL讀取圖片內容信息
 4 @RequestMapping(value="/readPhotoInfo1.do",method=RequestMethod.POST)
 5 public  String readPhotoInfo1(HttpServletRequest request,HttpServletResponse response) throws IOException{
 6     response.setContentType("text/html; charset=utf-8");
 7     //js里通過ajax傳遞過來的圖片URL
 8     String photoURL = request.getParameter("photoURL");
 9     URL photo_url = new URL(photoURL);    
10     HttpURLConnection conn = (HttpURLConnection)photo_url.openConnection();    
11     conn.setConnectTimeout(3*1000);  
12     //防止屏蔽程序抓取而返回403錯誤  
13     conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");  
14     //得到輸入流  
15     InputStream inputStream = conn.getInputStream();    
16     byte[] buff = CertificateRecognition.getBytesFromInputStream(inputStream);     
17         
18     //API的地址
19     String url = "https://api-cn.faceplusplus.com/cardpp/v1/ocridcard";
20     HashMap<String, String> map = new HashMap<>();
21     HashMap<String, byte[]> byteMap = new HashMap<>();
22     map.put("api_key", "你的api_key");
23     map.put("api_secret", "你的api_secret");
24     map.put("return_landmark", "1");
25     map.put("return_attributes", "gender,age,smiling,headpose,facequality,blur,eyestatus,emotion,ethnicity,beauty,mouthstatus,eyegaze,skinstatus");
26     byteMap.put("image_file", buff);
27     PrintWriter out = response.getWriter();
28 
29     callPost(url, map, byteMap, out);
30     out.close();
31     return null;
32 }

 

 1 //調用CertificateRecognition中的post方法
 2 private void callPost(String url, HashMap<String, String> map, HashMap<String, byte[]> byteMap, PrintWriter pw) {
 3    try{
 4       byte[] bacd = CertificateRecognition.post(url, map, byteMap);
 5       this.photoInfo = new String(bacd);
 6       pw.println(photoInfo);
 7       System.out.println(photoInfo);
 8    }catch (Exception e) {
 9       e.printStackTrace();
10    }
11 }

 

 

②通過本地上傳方式

當選擇本地圖片,由於綁定js的change事件,首先完成修改img標簽的背景圖片,這里的js得到的是本地圖片的base64編碼,並將其傳給'readPhoto2'函數。該函數將的base64編碼通過AJAX異步請求傳至Controller層,Controller層首先需要對圖片的base64編碼進行截取(前綴data:image/ jpeg; base64,為無效字符串),並調整異常數據,再將其寫入本地一個規定的絕對路徑。然后同理通過上述代碼轉為字節型數組,並將其put至HashMap中作為參數之一。這時再調用post函數,得到返回值並轉為JSON格式返回至' readPhoto2'函數,該函數再取值通過id賦值給相應的標簽。參考代碼如下。

 1 $("#admin_upload_photo").change(function(){    
 2       if(window.FileReader){       //chrome,firefox7+,opera,IE10,IE9,IE9也可以用濾鏡來實現
 3            oFReader = new FileReader();
 4            oFReader.readAsDataURL(this.files[0]);
 5            oFReader.onload = function (oFREvent) {
 6                document.getElementById('bg-model4_img').src = oFREvent.target.result;
 7                var base64 = oFREvent.target.result;
 8                alert(base64);
 9                readPhoto2(base64);
10            }; 
11       }
12 });

 

 1 /*通過絕對路徑讀取圖片*/
 2 function readPhoto2(base64){ 
 3     $.post("readPhotoInfo2.do",{base64},function(data){
 4         document.getElementById("name").innerHTML = data.cards[0].name;
 5         document.getElementById("sex").innerHTML = data.cards[0].gender;
 6         document.getElementById("race").innerHTML = data.cards[0].race;
 7         document.getElementById("birthday").innerHTML = data.cards[0].birthday;
 8         document.getElementById("address").innerHTML = data.cards[0].address;
 9         document.getElementById("idcard_num").innerHTML = data.cards[0].id_card_number;
10         if(data.cards[0].side == "front"){
11             document.getElementById("admin_side").innerHTML = "人像面";
12         }else{
13             document.getElementById("admin_side").innerHTML = "國徽面";
14         }
15         document.getElementById("admin_time_used").innerHTML = data.time_used + "ms";
16     },"json");
17 }

 

 1 //根據圖片絕對路徑讀取圖片內容信息
 2 @RequestMapping(value="/readPhotoInfo2.do",method=RequestMethod.POST)
 3 public  String readPhotoInfo2(HttpServletRequest request,HttpServletResponse response) throws IOException{
 4     response.setContentType("text/html; charset=utf-8");
 5     //js里通過ajax傳遞過來的圖片base64編碼
 6     String base64 = request.getParameter("base64");
 7     int size = base64.indexOf(",");  //截取第一個,號后面的字符串
 8     System.out.println(size);  //21
 9     
10     String substr = base64.substring(22); 
11     
12     BASE64Decoder decoder = new BASE64Decoder();
13     try 
14     {           
15         byte[] b = decoder.decodeBuffer(substr);
16         for(int i=0;i<b.length;++i)  //調整異常數據
17         {
18             if(b[i]<0){
19                 b[i] += 256;
20             }
21         }            
22         String imgFilePath = "e:/base.png";   //新生成的圖片存放路徑
23         OutputStream out = new FileOutputStream(imgFilePath);    
24         out.write(b);
25         out.flush();
26         out.close();           
27         
28         File file = new File(imgFilePath);
29         byte[] buff = CertificateRecognition.getBytesFromFile(file);
30         
31         //API的地址
32         String url = "https://api-cn.faceplusplus.com/cardpp/v1/ocridcard";
33         HashMap<String, String> map = new HashMap<>();
34         HashMap<String, byte[]> byteMap = new HashMap<>();
35         map.put("api_key", "你的api_key");
36         map.put("api_secret", "你的api_secret");
37         map.put("return_landmark", "1");
38         map.put("return_attributes", "gender,age,smiling,headpose,facequality,blur,eyestatus,emotion,ethnicity,beauty,mouthstatus,eyegaze,skinstatus");
39         byteMap.put("image_file", buff);
40         PrintWriter pw = response.getWriter();
41 
42         callPost(url, map, byteMap, pw);
43         pw.close();
44         
45     } 
46     catch (Exception e){
47        e.printStackTrace();
48     }
49     return null;
50 }

 

 

項目效果圖如下(證件圖片是在網上任意找的一張圖片,不針對於任何人)。

 

 

如有疏漏錯誤之處,還請不吝賜教!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM