zoukankan      html  css  js  c++  java
  • 通过调用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 }

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

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

  • 相关阅读:
    RSA私钥加密研究
    贪吃蛇 WPF
    随手写 --- 贪吃蛇
    canvas总结:线段宽度与像素边界
    canvas总结:元素大小与绘图表面大小
    【原】YUI Test自动化测试实例详解
    【译】Optimize for mobile-移动端优化
    【原】从一个bug浅谈YUI3组件的资源加载
    【译】Optimize caching-缓存优化
    【原】YUI3:js加载过程及时序问题
  • 原文地址:https://www.cnblogs.com/yijialong/p/9072405.html
Copyright © 2011-2022 走看看