阿里云 aliyun 人脸识别(1:N) java spring 小程序 小程序上传多图 阿里云oss

前段时间开发一个小程序需要使用到阿里云(1:N)人脸识别的服务,查询资料发现网上并没有详细的教程,而官方的api文档也写得很简略,于是就有了如下教程,希望能帮助到大家。

目录

服务开通

人脸识别服务开通

oss存储服务开通

代码部分

人脸识别

①pom.xml

②face_detect_util

③代码讲解:

oss上传

①pom.xml

②OSS_Util 

③小程序前端

最后的结果:


服务开通

人脸识别服务开通

注册阿里云账户后,进入人脸人体控制台(阿里云登录 - 欢迎登录阿里云,安全稳定的云计算服务平台),进行对人脸人体API调用量的购买。目前阿里云上所有人脸人体的接口都是2QPS((Query Per Second):每秒请求数)免费,足够开发时学习使用。

oss存储服务开通

进入oss控制台(阿里云登录 - 欢迎登录阿里云,安全稳定的云计算服务平台),右侧有一块Bucket管理,点击创建Bucket来得到一块存储空间。个人对Bucket的理解就像是database中的一个个table,是用户用来管理所存储对象的存储空间。一个oss中可以拥有许多Bucket,但是每个Bucket的名称都是唯一的。由于人脸人体的url只支持上海的oss链接,所以创建华东2的Bucket。创建好之后便可以使用阿里云的人脸识别技术了。

代码部分

这里使用java代码作为实例,前端为需要人脸识别功能的小程序,后端使用Springboot框架。

人脸识别

①pom.xml

        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
            <version>4.1.1</version>
        </dependency>

②face_detect_util

需要先得到阿里云的access_key_id(如何创建AccessKey_访问控制-阿里云帮助中心);

package com.zhiqi.wayhome.Util;

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 com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhiqi.wayhome.Bean.Face_msg;

import java.util.Map;

public class face_detect_util {

    //DefaultProfile.getProfile的参数分别是地域,access_key_id, access_key_secret
    public static DefaultProfile profile = DefaultProfile.getProfile("cn-shanghai", "xxx", "xxx");//这里要改成自己的
    public static DefaultAcsClient client = new DefaultAcsClient(profile);
    public static ObjectMapper mapper=new ObjectMapper();


    /**
     * AddFaceEntity用于添加人脸样本 添加了人脸样本后才能添加人脸数据
     * 只有在用户上传第一张照片时调用这个接口 之后就只需要添加人脸数据即可
     * @param EntityId 用身份证号码来标识
     *
     */
    public static void AddFaceEntity(String EntityId){
        CommonRequest request = new CommonRequest();
        request.setMethod(MethodType.POST);
        request.setVersion("2019-12-30");
        request.setDomain("facebody.cn-shanghai.aliyuncs.com");
        request.putBodyParameter("Action", "AddFaceEntity");
        request.putBodyParameter("DbName", "Wayhome");
        request.putBodyParameter("EntityId", EntityId);
        CommonResponse response = null;
        try {
            response = client.getCommonResponse(request);
        } catch (ClientException e) {
            e.printStackTrace();
        }
        System.out.println(response.getData());

    }



    /**
     * AddFace接口用于向人脸样本中添加人脸数据
     * @param
     * @param EntityId 添加人脸的身份证号
     * @param imageUrl 检测图片的URL
     */
    public static int AddFace(String EntityId,String imageUrl)
    {
        CommonRequest request = new CommonRequest();
        request.setMethod(MethodType.POST);
        request.setVersion("2019-12-30");
        request.setDomain("facebody.cn-shanghai.aliyuncs.com");
        request.setAction("AddFace");
        request.putBodyParameter("DbName", "Wayhome");
        request.putBodyParameter("EntityId", EntityId);
        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());
        //得到这张图片的FaceId 并存到数据库中
        Face_msg face_msg=null;
        String s=response.getData();
        String[] ss=s.split("FaceId");
        String a=ss[1].substring(3,ss[1].length()-3);
        return Integer.parseInt(a);


    }

    /**
     * DeleteFace接口用于从人脸库中删除某张人脸数据
     * @param FaceId 删除指定FaceId的图片
     * @throws ClientException
     */
    public static void DeleteFace(int FaceId)  {
        CommonRequest request = new CommonRequest();
        request.setMethod(MethodType.POST);
        request.setVersion("2019-12-30");
        request.setDomain("facebody.cn-shanghai.aliyuncs.com");

        request.setAction("DeleteFace");
        request.putBodyParameter("DbName", "Wayhome");
        request.putBodyParameter("FaceId", FaceId);
        CommonResponse response = null;
        try {
            response = client.getCommonResponse(request);
        } catch (ClientException e) {
            e.printStackTrace();
        }
        System.out.println(response.getData());
    }

    /**
     * DeleteFaceEntity接口用于从人脸库中删除人脸实体
     * @param EntityId 在任务结束后清除该走失者的人脸实体

     * @throws ClientException
     */
    public static void DeleteFaceEntity(String EntityId)  {
        CommonRequest request = new CommonRequest();
        request.setMethod(MethodType.POST);
        request.setVersion("2019-12-30");
        request.setDomain("facebody.cn-shanghai.aliyuncs.com");
        request.setAction("DeleteFaceEntity");
        request.putBodyParameter("DbName", "Wayhome");
        request.putBodyParameter("EntityId", EntityId);
        CommonResponse response = null;
        try {
            response = client.getCommonResponse(request);
        } catch (ClientException e) {
            e.printStackTrace();
        }
        System.out.println(response.getData());
    }

    /**
     *
     * @param ImageUrl
     */
    public static String SearchFace(String ImageUrl) {
        CommonRequest request = new CommonRequest();
        request.setMethod(MethodType.POST);
        request.setVersion("2019-12-30");
        request.setDomain("facebody.cn-shanghai.aliyuncs.com");
        request.setAction("SearchFace");
        request.putBodyParameter("DbName", "Wayhome");
        request.putBodyParameter("ImageUrl", ImageUrl);
        request.putBodyParameter("Limit", 1);
        CommonResponse response = null;
        try {
            response = client.getCommonResponse(request);
        } catch (ClientException e) {
            e.printStackTrace();
        }
        String s=response.getData();
        System.out.println(s);
        return s;
    }
}

③代码讲解:

使用人脸识别的顺序-->创建人脸数据库(可手动也可代码,目前免费用户一人只能创建一个人脸库)-->创建人脸实体(一个人脸实体代表一个人,可以有几张照片)-->为人脸实体添加数据(一个实体最多用五张图片来训练)-->上传图片与人脸库中的所有实体进行比对(1:N)。

①创建人脸库:我是手动创建人脸库的,登录到人脸人体控制台(阿里云登录 - 欢迎登录阿里云,安全稳定的云计算服务平台)中,点击以下按钮,进入数据库管理中新建人脸库,我的取名为Wayhome。

②创建人脸实体:代码中的AddFaceEntity(String EntityId)函数。调用的也是AddFaceEntity接口,接口文档(AddFaceEntity_视觉智能开放平台-人脸人体_API文档-阿里云OpenAPI开发者门户),查看文档发现,请求的参数列表如下:

其中DbName为之前创建的人脸数据库名,我创建的为Wayhome;EntityId为创建的人脸实体的ID,一般使用该人的唯一标识。如身份证号、员工号等。Lables可传可不传,可以是该人的姓名作为备注。

注意:要用POST方法调用接口,传入的参数中要有SDK的版本:request.setVersion("2019-12-30");版本号从文档中查看(文档的网址中也有版本号)。

之后的接口就很类似了,这里不一一演示。

由于人脸识别传入的faceimage需要是自家oss的链接,我一开始自己搭建了上传图片的服务器,但是发现传入图片链接后报错,查阅资料传入的参数必须是oss的链接,接下来介绍一下小程序上传多张照片到oss并返回URL链接。

oss上传

①pom.xml

        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>2.7.0</version>
        </dependency>

②OSS_Util 

package com.zhiqi.wayhome.Util;

import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.Random;

public class OSS_Util {
    protected static final Logger log = LoggerFactory.getLogger(OSS_Util.class);
    private static String endpoint="oss-cn-shanghai.aliyuncs.com";
    private static String accessKeyId="LTAI5tE4awy6GwWiHA4sHkd5";
    private static String accessKeySecret="5E3X23XuLBO71YPW01ZXSdfgresG28";
    private static String bucketName="wayhome";
    //文件存储目录
    private static String filedir = "userImg/";
    /**
     *
     * 上传图片
     * @param file
     * @return
     */
    public static String uploadImg2Oss(MultipartFile file) {
        if (file.getSize() > 1024 * 1024 *20) {
            return "图片太大";//RestResultGenerator.createErrorResult(ResponseEnum.PHOTO_TOO_MAX);
        }
        String originalFilename = file.getOriginalFilename();
        String substring = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase();
        Random random = new Random();
        String name = random.nextInt(10000) + System.currentTimeMillis() + substring;
        try {
            InputStream inputStream = file.getInputStream();
            uploadFile2OSS(inputStream, name);
            return name;//RestResultGenerator.createSuccessResult(name);
        } catch (Exception e) {
            return "上传失败";//RestResultGenerator.createErrorResult(ResponseEnum.PHOTO_UPLOAD);
        }
    }

    /**
     * 上传图片获取fileUrl
     * @param instream
     * @param fileName
     * @return
     */
    private static String uploadFile2OSS(InputStream instream, String fileName) {
        String ret = "";
        try {
            //创建上传Object的Metadata
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(instream.available());
            objectMetadata.setCacheControl("no-cache");
            objectMetadata.setHeader("Pragma", "no-cache");
            objectMetadata.setContentType(getcontentType(fileName.substring(fileName.lastIndexOf("."))));
            objectMetadata.setContentDisposition("inline;filename=" + fileName);
            //上传文件

            OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
            PutObjectResult putResult = ossClient.putObject(bucketName, filedir + fileName, instream, objectMetadata);
            ret = putResult.getETag();
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        } finally {
            try {
                if (instream != null) {
                    instream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return ret;
    }

    public static String getcontentType(String FilenameExtension) {
        if (FilenameExtension.equalsIgnoreCase(".bmp")) {
            return "image/bmp";
        }
        if (FilenameExtension.equalsIgnoreCase(".gif")) {
            return "image/gif";
        }
        if (FilenameExtension.equalsIgnoreCase(".jpeg") ||
                FilenameExtension.equalsIgnoreCase(".jpg") ||
                FilenameExtension.equalsIgnoreCase(".png")) {
            return "image/jpg";
        }
        if (FilenameExtension.equalsIgnoreCase(".html")) {
            return "text/html";
        }
        if (FilenameExtension.equalsIgnoreCase(".txt")) {
            return "text/plain";
        }
        if (FilenameExtension.equalsIgnoreCase(".vsd")) {
            return "application/vnd.visio";
        }
        if (FilenameExtension.equalsIgnoreCase(".pptx") ||
                FilenameExtension.equalsIgnoreCase(".ppt")) {
            return "application/vnd.ms-powerpoint";
        }
        if (FilenameExtension.equalsIgnoreCase(".docx") ||
                FilenameExtension.equalsIgnoreCase(".doc")) {
            return "application/msword";
        }
        if (FilenameExtension.equalsIgnoreCase(".xml")) {
            return "text/xml";
        }
        return "image/jpg";
    }

    /**
     * 获取图片路径
     * @param fileUrl
     * @return
     */
    public static String getImgUrl(String fileUrl) {
        if (!StringUtils.isEmpty(fileUrl)) {
            String[] split = fileUrl.split("/");
            String url = getUrl(filedir + split[split.length - 1]);
            return url;
        }
        return null;
    }

    /**
     * 获得url链接
     *
     * @param key
     * @return
     */
    public static String getUrl(String key) {
        // 设置URL过期时间为10年 3600l* 1000*24*365*10
        // 如果不设置则URL的有效时间很短
        Date expiration = new Date(new Date().getTime() + 3600L * 1000 * 24 * 365 * 10);
        // 生成URL
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        URL url = ossClient.generatePresignedUrl(bucketName, key, expiration);
        if (url != null) {
            return url.toString();
        }
        return null;
    }


    /**
     * 多图片上传
     * @param fileList
     * @return
     */
    public static String checkList(List<MultipartFile> fileList) {
        String fileUrl = "";
        String str = "";
        String photoUrl = "";
        for(int i = 0;i< fileList.size();i++){
            fileUrl = uploadImg2Oss(fileList.get(i));
            str = getImgUrl(fileUrl);
            if(i == 0){
                photoUrl = str;
            }else {
                photoUrl += "," + str;
            }
        }
        return photoUrl.trim();
    }

    /**
     * 单个图片上传
     * @param file
     * @return
     */
    public static String checkImage(MultipartFile file){
        String fileUrl = uploadImg2Oss(file);
        String str = getImgUrl(fileUrl);
        return str.trim();
    }




    /**
     * 删除oss内的文件
     *
     */

    public static void removeFile(String img_url) {
        int i1=img_url.indexOf('/');
        int i2=img_url.indexOf('/',i1+1);
        int i3=img_url.indexOf('/',i2+1);
        int i4=img_url.indexOf("?",i3+1);
        String substring=img_url.substring(i3+1,i4);
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        try {
            // 删除文件。如需删除文件夹,请将ObjectName设置为对应的文件夹名称。如果文件夹非空,则需要将文件夹下的所有object删除后才能删除该文件夹。
            ossClient.deleteObject(bucketName, substring);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 关闭OSSClient。
        ossClient.shutdown();

    }


}

使用代码时只需要修改以下部分:

  protected static final Logger log = LoggerFactory.getLogger(OSS_Util.class);
    private static String endpoint="oss-cn-shanghai.aliyuncs.com";
    private static String accessKeyId="xxx";//人脸识别那讲的accessKeyId
    private static String accessKeySecret="xxxxx";
    private static String bucketName="wayhome";//之前创建的bucket名称
    //文件存储目录
    private static String filedir = "userImg/";//自定

单图片和多图片上传分别调用checkImage()和checkList()方法,返回图片的url。

删除文件部分代码的解释:

图片返回的url样例(http://wayhome.oss-cn-shanghai.aliyuncs.com/userImg/1618904390858.jpg?Expires=1934264388&OSSAccessKeyId=LTAI5tE4awy6GwWiHA4sHLd5&Signature=9J%2FQ1A%2F29y2XTPpBVudnW726bek%3D

所以文件在Bucket中存储的的路径为,即第三个‘/’到‘?’之间的部分,所以获取删除文件的目录为以下代码。

public static void removeFile(String img_url) {
        int i1=img_url.indexOf('/');
        int i2=img_url.indexOf('/',i1+1);
        int i3=img_url.indexOf('/',i2+1);
        int i4=img_url.indexOf("?",i3+1);
        String substring=img_url.substring(i3+1,i4);
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        try {
            // 删除文件。如需删除文件夹,请将ObjectName设置为对应的文件夹名称。如果文件夹非空,则需要将文件夹下的所有object删除后才能删除该文件夹。
            ossClient.deleteObject(bucketName, substring);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 关闭OSSClient。
        ossClient.shutdown();

    }

③小程序前端

data: {
    temp_img:null
}

 uploadd:function(i){
    var that=this;
    wx.uploadFile({ 
      url: '...',//输入你的上传接口 
      filePath: that.data.temp_img[i], //小程序的上传只能是一张一张图片上传 ,参数不能是一个数组。
      name: 'fileList',
      formData:{
        //这里面放补充参数
      },

//使用递归进行上传,会有错
      success: function (res) { 
        console.log(res);
        console.log(i);
        i++;
        if(i == length){ //当图片传完时,停止调用
            console.log('成功');
            wx.showToast({
                title: '上传成功!',
                duration: 1500,
                success: function(){
                    that.hideModal();
                }
            });
        }else {
            that.uploadd(i);    
        }
        //刷新页面
        that.onLoad();
        
      }, fail: function (err) { 
      console.log(err) 
      }
     
      });
  },
  upload_img(){

    //上传图片开始
      var that = this;
        wx.chooseImage({
          count: 5, // 最多可以选择的图片张数,默认9(人脸库每个人最多五张照片)
          sizeType: ['original'], // original 原图,compressed 压缩图,默认二者都有
          sourceType: ['album', 'camera'], // album 从相册选图,camera 使用相机,默认二者都有
          success: function (res) {
            // 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
            var tempFilePaths = res.tempFilePaths;
            wx.showToast({
              title: '正在上传',
              icon: 'loading',
              mask: true,
              duration: 1000
            });
            console.log(tempFilePaths);
            that.setData({
              temp_img:tempFilePaths
            })
  
            var i=0;
            that.uploadd(i);
  
  
  
          },
        });
    
    
    
    },
 

最后的结果:

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值