阿里人臉檢測實踐
java實現調用阿里人臉識別服務實現人臉檢測。在springboot項目中應用,根據前端傳回的經過Base64編碼的圖片,直接調用阿里人臉檢測服務實現檢測,並將檢測成功的圖片存入阿里雲OSS數據庫 ,並存儲返回的圖片url。
依賴
<!--阿里雲OSS依賴-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!--阿里雲SDK,人臉檢測-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>3.2.6</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-cms</artifactId>
<version>7.0.3</version>
</dependency>
方向枚舉類
此處根據個人需要,用其主要爲了滿足自身需要存儲上下左右四個方向的圖片。
public enum Direction {
UP, DOWN, LEFT, RIGHT
}
人臉檢測類
package com.tjkj.tongjiankeji.component;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.CommonsRequestLoggingFilter;
//import com.aliyuncs.CommonRequest;
//import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import sun.misc.BASE64Encoder;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Locale;
/**
* @Created with qml
* @author:qml
* @Date: 2019/9/4
* @Time: 9:44
* @Description
*/
@Component
public class FaceDetection {
//自己阿里雲的keyId
@Value("${oss.keyid}")
private static String accessKeyId;
//自己阿里雲的keySecert
@Value("${oss.keysecret}")
private static String accessKeySecret;
//人臉檢測URL
//可根據自己的需要使用人臉屬性檢測,人臉識別接口,阿里均已提供
private static String detectUrl = "https://dtplus-cn-shanghai.data.aliyuncs.com/face/detect";
//人臉角度閾值(用以判斷識別出的人臉,在我們需要的角度範圍內,角度不能太大)
private static float faceThreshold = 30;
//DefaultProfile.getProfile的參數分別是地域,access_key_id, access_key_secret
public static DefaultProfile profile = DefaultProfile.getProfile("cn-shanghai", accessKeyId, accessKeySecret);
public static DefaultAcsClient client = new DefaultAcsClient(profile);
//此方法可忽略,爲測試方法
public static void main(String[] args) {
//若要使用本地圖片,需要轉換成BASE64編碼
String image_url = "網絡圖片鏈接";
String url = "https://dtplus-cn-shanghai.data.aliyuncs.com/face/detect";
//請求頭,根據官方文檔設定參數。type=0時,爲網絡圖片,即image_url爲圖片鏈接
//type-1時,爲轉成Base64編碼的圖片,body="{\"type\": "+1+", \"content\": \"" + 圖片的String類型編碼 + "\"}";
String body = "{\"type\":\"0\", \"image_url\":\"https://chiyikou.oss-cn-beijing.aliyuncs.com/faceImage/face1.jpg\"}";
try {
FaceDetection faceDetection = new FaceDetection();
// System.out.println(faceDetection.sendPost(url, body, accessKeyId, accessKeySecret));
System.out.println(faceDetection.detection(body, Direction.UP));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 檢測圖片是不是
* @param body
* @param direction
* @return -2: 未知異常 -1:檢測失敗 0:方向不正確 1:檢測成功 2:檢測到的人臉不是1個
*/
public int detection(String body, Direction direction) {
try {
JSONObject jsonObject = JSONObject.parseObject(sendPost(detectUrl, body, accessKeyId, accessKeySecret));
System.out.println("檢測結果:" + jsonObject.toString());
if (jsonObject.getInteger("errno") == 0) {
if (jsonObject.getInteger("face_num") == 1) {
JSONArray jsonArray = jsonObject.getJSONArray("pose");
// System.out.println(jsonArray.getFloat(0));
//左右角度
float x = jsonArray.getFloat(0);
//上下角度
float y = jsonArray.getFloat(1);
System.out.println("x:" + x + " y:" + y);
switch (direction) {
case UP:
return -faceThreshold < y && y <= 0 && y < x && x < faceThreshold ? 1 : 0;
case DOWN:
return 0 <= y && y <= faceThreshold && y > x && x > -faceThreshold ? 1 : 0;
case LEFT:
return -faceThreshold < x && x <= 0 && x < y && y < faceThreshold ? 1 : 0;
case RIGHT:
return 0 <= x && x <= faceThreshold && x > y && y > -faceThreshold ? 1 : 0;
default:
return -2;
}
}else {
return 2;
}
}else {
System.out.println("檢測失敗!");
return -1;
}
} catch (Exception e) {
e.printStackTrace();
return -2;
}
}
// /**
// * DetectFace API 人臉檢測定位
// *
// * @param imageUrl 檢測人臉圖片的URL
// */
// public static void DetectFace(String imageUrl) {
// CommonsRequest request = new CommonRequest();
// request.setMethod(MethodType.POST);
// request.setDomain("face.cn-shanghai.aliyuncs.com");
// request.setVersion("2018-12-03");
// request.setAction("DetectFace");
// request.putBodyParameter("ImageUrl", imageUrl);
//// request.putBodyParameter("Content", "/9j/4AAQSkZJRgABA..."); //檢測圖片的內容,Base64編碼
// CommonResponse response = null;
// try {
// response = client.getCommonResponse(request);
// } catch (ClientException e) {
// e.printStackTrace();
// }
// System.out.println(response.getData());
// }
/*
* 計算MD5+BASE64
*/
public String MD5Base64(String s) {
if (s == null) {
return null;
}
String encodeStr = "";
byte[] utfBytes = s.getBytes();
MessageDigest mdTemp;
try {
mdTemp = MessageDigest.getInstance("MD5");
mdTemp.update(utfBytes);
byte[] md5Bytes = mdTemp.digest();
BASE64Encoder b64Encoder = new BASE64Encoder();
encodeStr = b64Encoder.encode(md5Bytes);
} catch (Exception e) {
throw new Error("Failed to generate MD5 : " + e.getMessage());
}
return encodeStr;
}
/*
* 計算 HMAC-SHA1
*/
public String HMACSha1(String data, String key) {
String result;
try {
SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(signingKey);
byte[] rawHmac = mac.doFinal(data.getBytes());
result = (new BASE64Encoder()).encode(rawHmac);
} catch (Exception e) {
throw new Error("Failed to generate HMAC : " + e.getMessage());
}
return result;
}
/*
* 等同於javaScript中的 new Date().toUTCString();
*/
public String toGMTString(Date date) {
SimpleDateFormat df = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z", Locale.UK);
df.setTimeZone(new java.util.SimpleTimeZone(0, "GMT"));
return df.format(date);
}
/*
* 發送POST請求
*/
public String sendPost(String url, String body, String ak_id, String ak_secret) throws Exception {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
int statusCode = 200;
try {
URL realUrl = new URL(url);
/*
* http header 參數
*/
String method = "POST";
String accept = "application/json";
String content_type = "application/json";
String path = realUrl.getFile();
String date = toGMTString(new Date());
// 1.對body做MD5+BASE64加密
String bodyMd5 = MD5Base64(body);
String stringToSign = method + "\n" + accept + "\n" + bodyMd5 + "\n" + content_type + "\n" + date + "\n"
+ path;
// 2.計算 HMAC-SHA1
String signature = HMACSha1(stringToSign, ak_secret);
// 3.得到 authorization header
String authHeader = "Dataplus " + ak_id + ":" + signature;
// 打開和URL之間的連接
URLConnection conn = realUrl.openConnection();
// 設置通用的請求屬性
conn.setRequestProperty("accept", accept);
conn.setRequestProperty("content-type", content_type);
conn.setRequestProperty("date", date);
conn.setRequestProperty("Authorization", authHeader);
// 發送POST請求必須設置如下兩行
conn.setDoOutput(true);
conn.setDoInput(true);
// 獲取URLConnection對象對應的輸出流
out = new PrintWriter(conn.getOutputStream());
// 發送請求參數
out.print(body);
// flush輸出流的緩衝
out.flush();
// 定義BufferedReader輸入流來讀取URL的響應
statusCode = ((HttpURLConnection)conn).getResponseCode();
if(statusCode != 200) {
in = new BufferedReader(new InputStreamReader(((HttpURLConnection)conn).getErrorStream()));
} else {
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
}
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
if (statusCode != 200) {
throw new IOException("\nHttp StatusCode: "+ statusCode + "\nErrorMessage: " + result);
}
return result;
}
/*
* GET請求
*/
public String sendGet(String url, String ak_id, String ak_secret) throws Exception {
String result = "";
BufferedReader in = null;
int statusCode = 200;
try {
URL realUrl = new URL(url);
/*
* http header 參數
*/
String method = "GET";
String accept = "application/json";
String content_type = "application/json";
String path = realUrl.getFile();
String date = toGMTString(new Date());
// 1.對body做MD5+BASE64加密
// String bodyMd5 = MD5Base64(body);
String stringToSign = method + "\n" + accept + "\n" + "" + "\n" + content_type + "\n" + date + "\n" + path;
// 2.計算 HMAC-SHA1
String signature = HMACSha1(stringToSign, ak_secret);
// 3.得到 authorization header
String authHeader = "Dataplus " + ak_id + ":" + signature;
// 打開和URL之間的連接
URLConnection connection = realUrl.openConnection();
// 設置通用的請求屬性
connection.setRequestProperty("accept", accept);
connection.setRequestProperty("content-type", content_type);
connection.setRequestProperty("date", date);
connection.setRequestProperty("Authorization", authHeader);
connection.setRequestProperty("Connection", "keep-alive");
// 建立實際的連接
connection.connect();
// 定義 BufferedReader輸入流來讀取URL的響應
statusCode = ((HttpURLConnection)connection).getResponseCode();
if(statusCode != 200) {
in = new BufferedReader(new InputStreamReader(((HttpURLConnection)connection).getErrorStream()));
} else {
in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
}
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
if (statusCode != 200) {
throw new IOException("\nHttp StatusCode: "+ statusCode + "\nErrorMessage: " + result);
}
return result;
}
}
阿里OSS上傳圖片類
package com.tjkj.tongjiankeji.utils;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.PutObjectResult;
import org.springframework.beans.factory.annotation.Value;
import java.io.InputStream;
import java.util.Date;
/**
* @Created with qml
* @author:qml
* @Date: 2019/8/28
* @Time: 10:06
* @Description
*/
public class OSSUtil {
//從OSS數據庫獲得
@Value("${oss.endpoint}")
private static String endpoint;
@Value("${oss.keyid}")
private static String accessKeyId;
@Value("${oss.keysecret}")
private static String accessKeySecret;
@Value("${oss.buckname}")
private static String bucketName";
@Value("${oss.facefloder}")
private static String floder;
private static String key = "https://chiyikou.oss-cn-beijing.aliyuncs.com/";
/**
* 上傳單個圖片
* @param filename
* @param inputStream
* @return
*/
public String uploadImageToOSS(String filename, InputStream inputStream) {
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
try {
ossClient.putObject(bucketName, floder + "/" + filename, inputStream);
String url = key + floder + "/" + filename;
return url;
}catch (Exception e) {
e.printStackTrace();
}finally {
ossClient.shutdown();
}
return null;
}
/**
* 上傳多個圖片
* @param filename
* @param inputStream
* @return
*/
public String[] uploadImageToOSS(String[] filename, InputStream[] inputStream) {
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
try {
String []url = new String[filename.length];
for (int i = 0; i < filename.length; i++) {
ossClient.putObject(bucketName, floder + "/" +filename[i], inputStream[i]);
url[i] = key + floder + "/" + filename[i];
}
return url;
}catch (Exception e) {
e.printStackTrace();
}finally {
ossClient.shutdown();
}
return null;
}
}