要说人脸检测、识别国内最好的还是face++,但是无奈,face++的技术支持太差了,既没有交流群,技术支持邮件也没人理。没办法,最后尝试使用百度的。
注意,虽然该服务表面上是免费的,但是对象存储BOS 是收费的,没有bos你没办法上传图片,不过也很便宜。
百度的人脸识别使用了rest风格的api,只需要简单的http请求即可。整个api的难点在于权限认证,
足足调了2天。
权限认证实现:
package com.baidubce;
import java.io.UnsupportedEncodingException;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Map;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Hex;
/**
* 认证字符串生成
* @author pc
*
*/
public class BceAuthString {
/**
* 生成BceAuthString(认证字符串)
*/
public String createBceAuthString(String accessKeyID, String secretAccessKey, String httpMethod, String path, Map header, String UTCTime){
String authStringPrefix = "bce-auth-v1/{accessKeyId}/{timestamp}/{expirationPeriodInSeconds}";
authStringPrefix = authStringPrefix.replace("{accessKeyId}", accessKeyID);
authStringPrefix = authStringPrefix.replace("{timestamp}", UTCTime);
authStringPrefix = authStringPrefix.replace("{expirationPeriodInSeconds}", "1800");
String canonicalRequest = this.createCanonicalRequest(httpMethod, path, header);
String signingKey = this.createSigningKey(secretAccessKey, authStringPrefix);
String signature = this.createSignature(signingKey, canonicalRequest);
String signedHeaders = createSignedHeaders(header);
String bceAuthString = authStringPrefix + "/" + signedHeaders + "/" + signature;
return bceAuthString;
}
/**
* 创建CanonicalRequest
* CanonicalRequest = HTTP Method + "\n" + CanonicalURI + "\n" + CanonicalQueryString + "\n" + CanonicalHeaders
*/
private String createCanonicalRequest(String httpMethod, String path, Map header){
httpMethod = httpMethod.toUpperCase();
if(path == null || path.trim().equals(""))
path = "";
String canonicalURI = path;
String canonicalQueryString = "";
int index = path.indexOf("?");
if(index != -1){
canonicalURI = path.substring(0, index);
canonicalQueryString = path.substring(index + 1);
}
//生成CanonicalURI
if(!canonicalURI.startsWith("/"))
canonicalURI = "/" + canonicalURI;
canonicalURI = uriEncode(canonicalURI, false);
//生成CanonicalQueryString
String[] queryArray = canonicalQueryString.split("&");
for(int i = 0; i
String item = queryArray[i];
if(item == null || item.trim().equals(""))
continue;
String key = item.split("=")[0];
String value = item.split("=")[1];
key = uriEncode(key, true);
value = uriEncode(value, true);
queryArray[i] = key + "=" + value;
}
Arrays.sort(queryArray);
StringBuffer sb = new StringBuffer();
for(int i = 0; i
String item = queryArray[i];
if(item == null || item.trim().equals(""))
continue;
sb.append(item + "&");
}
if(sb.length() > 0)
sb.deleteCharAt(sb.length() - 1);
canonicalQueryString = sb.toString();
//生成CanonicalHeaders
String[] headerArray = new String[header.size()];
index = 0;
for (Map.Entry entry : header.entrySet()) {
String key = entry.getKey().toLowerCase();
String value = entry.getValue().trim();
headerArray[index] = uriEncode(key, true) + ":" + uriEncode(value, true);
index++;
}
Arrays.sort(headerArray);
sb = new StringBuffer();
for(int i = 0; i
String item = headerArray[i];
sb.append(item + "\n");
}
String canonicalHeaders = sb.toString();
if(canonicalHeaders.length() > 0)
canonicalHeaders = canonicalHeaders.substring(0, canonicalHeaders.lastIndexOf("\n"));
return httpMethod + "\n" + canonicalURI + "\n" + canonicalQueryString + "\n" + canonicalHeaders;
}
/**
* 生成SigningKey
* @param input
* @param encodeSlash
* @return
*/
private String createSigningKey(String secretAccessKey, String authStringPrefix){
String signingKey = sha256Hex(secretAccessKey, authStringPrefix);
return signingKey;
}
/**
* 生成Signature
* @param input
* @param encodeSlash
* @return
*/
private String createSignature(String signingKey, String canonicalRequest){
String signature = sha256Hex(signingKey, canonicalRequest);
return signature;
}
/**
* 创建signedHeaders
* @param input
* @param encodeSlash
* @return
*/
private String createSignedHeaders(Map header){
String[] headerArray = new String[header.size()];
int index = 0;
for (Map.Entry entry : header.entrySet()) {
String key = entry.getKey().toLowerCase();
headerArray[index] = key;
index++;
}
Arrays.sort(headerArray);
StringBuffer sb = new StringBuffer();
for(int i = 0; i
String item = headerArray[i];
sb.append(item + ";");
}
if(sb.length() > 0)
sb.deleteCharAt(sb.length() - 1);
String signedHeaders = sb.toString();
return signedHeaders;
}
public String uriEncode(CharSequence input, boolean encodeSlash) {
StringBuilder result = new StringBuilder();
try {
for (int i = 0; i
char ch = input.charAt(i);
if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '_' || ch == '-' || ch == '~' || ch == '.') {
result.append(ch);
} else if (ch == '/') {
result.append(encodeSlash ? "%2F" : ch);
} else {
result.append(toHexUTF8(ch));
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result.toString();
}
private String toHexUTF8(char c){
try {
byte[] b = String.valueOf(c).getBytes(BceConstants.ENCODING);
for (int j = 0; j
int k = b[j];
if (k
k += 256;
return "%" + Integer.toHexString(k).toUpperCase();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "";
}
private String sha256Hex(String signingKey, String stringToSign) {
try {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(signingKey.getBytes(BceConstants.ENCODING), "HmacSHA256"));
return new String(Hex.encodeHex(mac.doFinal(stringToSign.getBytes(BceConstants.ENCODING))));
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
}