1. 程式人生 > >人臉識別(二)呼叫face++api實現人臉對比

人臉識別(二)呼叫face++api實現人臉對比

上次部落格簡單講了一下呼叫face++的api來檢測人臉。當然,生產環境中要實現複雜的需求光靠這麼簡單的呼叫一下api肯定是不行的。這次先來講一講face++中實現人臉對比的api並實現一些相對較為複雜的需求。
首先來看一看呼叫的人臉對比的api需要的東西:
face++呼叫人臉對比api的網址:

呼叫方法使用POST呼叫,需要傳的主要的引數如下:

官方傳參列表

從官方給出的傳參列表可以看出,api_key和api_secret無疑是必需要傳的,接下來的必傳的兩個引數是兩張圖片。上傳圖片一共有三種方式:你可以選擇上傳圖片的url,或者上傳圖片的二進位制流,還可以上傳以base64編碼的圖片資料。或者你假如不想上傳圖片,可以使用以前上傳的圖片直接比對。這時你只要提交以前上傳圖片後得到的face_token就行了。在之前我講呼叫人臉檢測的介面時,只要你上傳成功,返回值裡面就會帶著face_token這個引數。這裡值得一提的是,我們通過呼叫人臉檢測上傳的圖片只會被face++官方儲存一段時間然後刪除,若我們想要將我們上傳的照片長期儲存在face++官方的庫中,則需要呼叫FaceSet這個api,相當於在face++建立一個我們自己的圖片倉庫,將我們上傳的圖片存到裡面。
這裡先演示一個簡單的例子:我先呼叫face++的人臉檢測api(具體怎麼呼叫的可以看我上一篇部落格:

呼叫人臉檢測api地址),上傳了兩張圖片,如下:

這裡寫圖片描述

這裡寫圖片描述

圖片是我從網上隨便找的(侵刪)。上傳之後得到兩個face_token:72fc859abb56f7dc2c7d6e0700d251f8和90f86917d51c58dffc21c173fdfb7c7d,接著,我呼叫人臉對比的api,程式碼如下:

package com.example.demo;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpEntity; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.CloseableHttpClient
; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; public class Compare { public static void main(String[] args) throws Exception { // 設定網址 String url = "https://api-cn.faceplusplus.com/facepp/v3/compare"; // 建立引數佇列 List<BasicNameValuePair> formparams = new ArrayList<>(); formparams.add(new BasicNameValuePair("api_key", "your api key")); formparams.add(new BasicNameValuePair("api_secret", "your api secret")); formparams.add(new BasicNameValuePair("face_token1", "72fc859abb56f7dc2c7d6e0700d251f8")); formparams.add(new BasicNameValuePair("face_token2", "90f86917d51c58dffc21c173fdfb7c7d")); // 傳送請求 post(formparams,url); } /** * 傳送 post請求訪問本地應用並根據傳遞引數不同返回不同結果 */ public static void post(List<BasicNameValuePair> formparams,String url) { // 建立預設的httpClient例項. CloseableHttpClient httpclient = HttpClients.createDefault(); // 建立httppost HttpPost httppost = new HttpPost(url); UrlEncodedFormEntity uefEntity; try { uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8"); httppost.setEntity(uefEntity); System.out.println("executing request " + httppost.getURI()); CloseableHttpResponse response = httpclient.execute(httppost); try { HttpEntity entity = response.getEntity(); if (entity != null) { System.out.println("--------------------------------------"); System.out.println("Response content: " + EntityUtils.toString(entity, "UTF-8")); System.out.println("--------------------------------------"); } } finally { response.close(); } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e1) { e1.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { // 關閉連線,釋放資源 try { httpclient.close(); } catch (IOException e) { e.printStackTrace(); } } } }

這裡用java發了個http請求傳入了api_key,api_secret,face_token1,face_token2四個引數。呼叫成功後返回結果如下:

--------------------------------------
16:14:04.347 [main] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection [id: 0][route: {s}->https://api-cn.faceplusplus.com:443] can be kept alive indefinitely
16:14:04.347 [main] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection released: [id: 0][route: {s}->https://api-cn.faceplusplus.com:443][total kept alive: 1; route allocated: 1 of 2; total allocated: 1 of 20]
Response content: {"confidence": 67.485, "request_id": "1514708045,f3e7b3bd-015c-4189-a47c-88b32ef3a91a", "time_used": 585, "thresholds": {"1e-3": 62.327, "1e-5": 73.975, "1e-4": 69.101}}
--------------------------------------

看看response content裡面返回的引數:

  • confidence:67.485。

含義:比對結果置信度,範圍 [0,100],小數點後3位有效數字,數字越大表示兩個人臉越可能是同一個人。如果傳入圖片但圖片中未檢測到人臉,則無法進行比對,本欄位不返回。

  • “request_id”: “1514708045,f3e7b3bd-015c-4189-a47c-88b32ef3a91a”

用於區分每一次請求的唯一的字串。

  • “time_used”: 585

整個請求所花費的時間,單位為毫秒。

  • “thresholds”: {“1e-3”: 62.327, “1e-5”: 73.975, “1e-4”: 69.101}

一組用於參考的置信度閾值,包含以下三個欄位。每個欄位的值為一個 [0,100] 的浮點數,小數點後 3 位有效數字。

  • 1e-3:誤識率為千分之一的置信度閾值;
  • 1e-4:誤識率為萬分之一的置信度閾值;
  • 1e-5:誤識率為十萬分之一的置信度閾值;

如果置信值低於“千分之一”閾值則不建議認為是同一個人;如果置信值超過“十萬分之一”閾值,則是同一個人的機率非常高。請注意:閾值不是靜態的,每次比對返回的閾值不保證相同,所以沒有持久化儲存閾值的必要,更不要將當前呼叫返回的 confidence 與之前呼叫返回的閾值比較。如果傳入圖片但圖片中未檢測到人臉,則無法進行比對,本欄位不返回。

用置信度閾值和置信度做對比我們可以得出這樣的結果:置信度(67.485)達到了千分之一(62.327),但並未達到萬分之一(69.101)和十萬分之一(73.975)的閾值。所以可以認為兩張照片有可能是同一個人,但可能性不高。

因為之前上傳的圖片不能永久儲存,我先建立一個FaceSet,讓後將這兩張照片新增到faceset中去。建立faceset程式碼如下:

package com.example.demo;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

public class Compare {
    public static void main(String[] args) throws Exception {
//      設定網址
        String url = "https://api-cn.faceplusplus.com/facepp/v3/faceset/create"; 
//        建立引數佇列    
        List<BasicNameValuePair> formparams = new ArrayList<>();  
        formparams.add(new BasicNameValuePair("api_key", "your api key"));  
        formparams.add(new BasicNameValuePair("api_secret", "your api secret")); 
        formparams.add(new BasicNameValuePair("outer_id", "myface_1"));  
//      傳送請求
        post(formparams,url);
    }

    /** 
     * 傳送 post請求訪問本地應用並根據傳遞引數不同返回不同結果 
     */  
    public static void post(List<BasicNameValuePair> formparams,String url) {  
        // 建立預設的httpClient例項.    
        CloseableHttpClient httpclient = HttpClients.createDefault();  
        // 建立httppost    
        HttpPost httppost = new HttpPost(url);  
        UrlEncodedFormEntity uefEntity;  
        try {  
            uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8");  
            httppost.setEntity(uefEntity);  
            System.out.println("executing request " + httppost.getURI());  
            CloseableHttpResponse response = httpclient.execute(httppost);  
            try {  
                HttpEntity entity = response.getEntity();  
                if (entity != null) {  
                    System.out.println("--------------------------------------");  
                    System.out.println("Response content: " + EntityUtils.toString(entity, "UTF-8"));  
                    System.out.println("--------------------------------------");  
                }  
            } finally {  
                response.close();  
            }  
        } catch (ClientProtocolException e) {  
            e.printStackTrace();  
        } catch (UnsupportedEncodingException e1) {  
            e1.printStackTrace();  
        } catch (IOException e) {  
            e.printStackTrace();  
        } finally {  
            // 關閉連線,釋放資源    
            try {  
                httpclient.close();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
    }
}

這裡我只是將上面的程式碼修改了傳入的引數,將url改為:https://api-cn.faceplusplus.com/facepp/v3/faceset/create。除了一直要傳入的api_key和api_secret外,還傳入了outer_id這個引數,用來指定我的faceset的唯一標識,因為face++允許我們建立多個faceset,隨意還是加一個唯一標識好點。返回引數如下:

--------------------------------------
17:18:04.581 [main] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection [id: 0][route: {s}->https://api-cn.faceplusplus.com:443] can be kept alive indefinitely
17:18:04.581 [main] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection released: [id: 0][route: {s}->https://api-cn.faceplusplus.com:443][total kept alive: 1; route allocated: 1 of 2; total allocated: 1 of 20]
Response content: {"faceset_token": "9cb520b964d58b3484565f6788ac750a", "time_used": 110, "face_count": 0, "face_added": 0, "request_id": "1514711886,953de53f-9c22-4aca-904f-2ffff88761a1", "outer_id": "myface_1", "failure_detail": []}
--------------------------------------

看到返回引數中faceset_token有值,就知道操作成功了。接下來我們把之前上傳的圖片加到faceset中,改變引數如下:

public static void main(String[] args) throws Exception {
//      設定網址
        String url = "https://api-cn.faceplusplus.com/facepp/v3/faceset/addface";
//        建立引數佇列    
        List<BasicNameValuePair> formparams = new ArrayList<>();  
        formparams.add(new BasicNameValuePair("api_key", "your api key"));  
        formparams.add(new BasicNameValuePair("api_secret", "your api secret")); 
        formparams.add(new BasicNameValuePair("outer_id", "myface_1"));  
        formparams.add(new BasicNameValuePair("face_tokens", "72fc859abb56f7dc2c7d6e0700d251f8"));    
//      傳送請求
        post(formparams,url);
    }

將之前我新增的faceset的識別符號myface_id傳入,同時傳入之前上傳圖片的face_token,請求完成得到一下引數:

Response content: {"faceset_token": "9cb520b964d58b3484565f6788ac750a", "time_used": 627, "face_count": 1, "face_added": 1, "request_id": "1514720178,9c0c43af-9923-461c-952e-f83f64f8f3e8", "outer_id": "myface_1", "failure_detail": []}

看到face_count為1代表當前這個faceset的存放照片個數,face_added為1表示成功添加了一個。至此,上傳的照片就已經永久儲存在了face++官方伺服器上。

至此,生產環境需要的主要的api我已經講的差不多了。本來計劃講一講具體的業務的實現的,但由於時間有限,決定留到下次部落格再講,這裡先把需要實現的業務給出來:

這裡寫圖片描述

下次部落格的時候就將這個需求實現一下。