通过调用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 }

项目效果图如下(证件图片是在网上任意找的一张图片,不针对于任何人)。

如有疏漏错误之处,还请不吝赐教!

原文地址:https://www.cnblogs.com/yijialong/p/9072405.html