Zzz-

首先感谢虹软,是你们提供这么好的SDK支撑了我们的想象力!

这是一个用javav编写的可视化应用,用户通过自己的脸和计算机进行交互,计算机则通过萌萌女孩的语音和用户对话。
核心程序就是利用ArcFace2.0识别性别、年龄,但是为了获得正面脸,会根据ArcFace2.0的人脸3D角度、用语音提醒用户,这是一个的互动环节。最后,程序会幽默的、萌萌的告诉用户他的性别、年龄。

获取SDK 请戳这里

完整的项目源码、可执行程序,放在百度网盘:链接: https://pan.baidu.com/s/1eHF66l111S3Rs0VaS7v_LA
提取码: ffag

其中主要的3个java文件,代码如下:

=====================================
HowOldAreU.java
=====================================
package app;

import java.awt.EventQueue;
import javax.swing.JFrame;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.awt.BorderLayout;
import com.alibaba.fastjson.JSONArray;
import com.arcsoft.face.FaceEngine;
import com.github.sarxos.webcam.Webcam;
import com.github.sarxos.webcam.WebcamPanel;
import tools.MyFunc;
import javax.swing.JOptionPane;

/*这是一个用javav编写的可视化应用,用户通过自己的脸和计算机进行交互,计算机则通过萌萌女孩的语音和用户对话。
核心程序就是利用ArcFace2.0识别性别、年龄,但是为了获得正面脸,会根据ArcFace2.0的人脸3D角度、用语音提醒用户,这是一个的互动环节。
最后,程序会幽默的、萌萌的告诉用户他的性别、年龄。

作者:huanghua8080@126.com
*/

public class HowOldAreU {

        //应用根目录
        public static String fs = File.separator;
        public final static String localPath = System.getProperty("user.dir")+fs;
        public final static String soundDir = localPath+"sound"+fs;
        //
        public static Webcam camera = null;
        private JFrame frame;
        //
        public static FaceEngine faceEngine = null;
        @SuppressWarnings("rawtypes")
        public static List FaceFeature = new ArrayList<Map<String, String>>();
        public static JSONArray aryFFTime = new JSONArray();
        public static JSONArray aryFFCnt = new JSONArray();
        public static String lastTime = "2019-01-09 13:30:00";
        public static int faceCnt = 0;

        /**
         * Launch the application.
         */
        public static void main(String[] args) {
                
                //判断程序是否已经运行
                String s = localPath+"lockApp.txt";
                //
                RandomAccessFile raf = null;
                try {
                        raf = new RandomAccessFile(new File(s), "rws");
                } catch (FileNotFoundException e1) {
                        JOptionPane.showMessageDialog(null, "独占文件时发生异常。"+e1, "错误",JOptionPane.ERROR_MESSAGE);
                        System.exit(0);
                }
                FileChannel fcin = raf.getChannel();
                FileLock flin = null;
                try {
                        flin = fcin.tryLock();
                } catch (Exception e) {
                        JOptionPane.showMessageDialog(null, "锁文件时发生异常:"+e, "错误",JOptionPane.ERROR_MESSAGE);
                        System.exit(0);
                }
            if (flin == null) {
                        JOptionPane.showMessageDialog(null, "程序已在运行,不可重复。", "错误",JOptionPane.ERROR_MESSAGE);
                        System.exit(0);
                }
            
                s = "D:\\Dev\\ec_workspace\\cs1914age";
                if(!s.equals(System.getProperty("user.dir"))) {
                        if(args.length == 0) {
                                JOptionPane.showMessageDialog(null, "没有入参,程序将终止。", "错误",JOptionPane.ERROR_MESSAGE);
                                System.exit(0);
                                return;
                        }
                        if(!"age".equals(MyFunc.strTrim(args[0]).toLowerCase())) {
                                JOptionPane.showMessageDialog(null, "入参错误,程序将终止。", "错误",JOptionPane.ERROR_MESSAGE);
                                System.exit(0);
                                return;
                        }
                }
                
            //获取摄像头
                camera = Webcam.getDefault();
                if (camera == null) {
                        JOptionPane.showMessageDialog(null, "摄像头获取失败。", "错误",JOptionPane.ERROR_MESSAGE);
                        return;
                }
                
                //初始化人脸引擎
                s = HowOldAreUAs.initEngine();
                if(!"".equals(s)) {
                        JOptionPane.showMessageDialog(null, s, "错误",JOptionPane.ERROR_MESSAGE);
                        System.exit(0);
                        return;
                }
                
                //启动窗体
                EventQueue.invokeLater(new Runnable() {
                        public void run() {
                                try {
                                        HowOldAreU window = new HowOldAreU();
                                        window.frame.setVisible(true);                                        
                                } catch (Exception e) {
                                        e.printStackTrace();
                                }
                        }
                });
        }

        /**
         * Create the application.
         */
        public HowOldAreU() {
                initialize();
        }

        /**
         * Initialize the contents of the frame.
         */
        private void initialize() {                
                //
                frame = new JFrame();
                frame.setTitle("猜年龄");
                frame.setBounds(100, 100, 610, 370);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.getContentPane().setLayout(new BorderLayout(0, 0));
                frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
                frame.setUndecorated(true);//去边框

                //摄像头加载到面板
                WebcamPanel panel = new WebcamPanel(camera);
                frame.getContentPane().add(panel, BorderLayout.CENTER);
                
                //启动声音
                HowOldAreUAs.playSound(100);                

                //线程(识别频率:毫秒)
                Timer timerMain = new Timer();
                timerMain.scheduleAtFixedRate(new TimerTask() {
                        public void run() {
                                if (camera != null) {
                                        HowOldAreUAs.photo();
                                }
                        }
                }, 0, 500);

        }

}


======================
HowOldAreUAs
====================================
package app;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.arcsoft.face.AgeInfo;
import com.arcsoft.face.Face3DAngle;
import com.arcsoft.face.FaceFeature;
import com.arcsoft.face.FaceInfo;
import com.arcsoft.face.FaceSimilar;
import com.arcsoft.face.FunctionConfiguration;
import com.arcsoft.face.GenderInfo;
import com.arcsoft.face.Rect;
import com.arcsoft.face.enums.ImageFormat;
import com.sun.jna.Platform;

import app.FaceAbout.ImageInfo;
import tools.MyFunc;
import tools.SoundPlay;

public class HowOldAreUAs {
        public static final int recoFreq = 60;//同一人不重复识别时间(秒)
        public static final int scoreThreshold = 70;//人脸相似度阀值
        //3D角度阀值
        public static final BigDecimal yes3d = new BigDecimal("5");
        
        //拍照
        @SuppressWarnings("unchecked")
        public static void photo() {
                int rtn=-1,sex=-1,age=-1;
                
                //当前时间
                String nowTime = MyFunc.getSvrTime("yyyy-MM-dd HH:mm:ss");
                
                //不重复识别时间(去除过期的)
                for(int n=HowOldAreU.aryFFTime.size()-1;n>=0;n--) {
                        if(MyFunc.datetimeSub(HowOldAreU.aryFFTime.get(n).toString(), nowTime) >= recoFreq) {
                                HowOldAreU.aryFFTime.remove(n);
                                HowOldAreU.aryFFCnt.remove(n);
                                HowOldAreU.FaceFeature.remove(n);
                        }
                }
                
                //拍照
                BufferedImage cameraImg = HowOldAreU.camera.getImage();
                
                //找脸
        List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>();
                ImageInfo imageInfo = new FaceAbout().bufferedImage2ImageInfo(cameraImg);
                HowOldAreU.faceEngine.detectFaces(imageInfo.getRgbData(), imageInfo.getWidth(), imageInfo.getHeight(), ImageFormat.CP_PAF_BGR24, faceInfoList);
                int cnt = faceInfoList.size();
                if (cnt == 0) {
                        //5分钟后,如果没有人来,则呼唤
                        if(MyFunc.datetimeSub(HowOldAreU.lastTime, nowTime) > 300) {
                                HowOldAreU.lastTime = nowTime;
                                playSound(200);
                        }
                        return;
                }
                HowOldAreU.lastTime = nowTime;

                //找最大脸(第一张脸即为最大脸)
                FaceInfo oneFace = faceInfoList.get(0);

                //提取脸纹
        FaceFeature CmFeature = new FaceFeature();
                rtn = HowOldAreU.faceEngine.extractFaceFeature(imageInfo.getRgbData(), imageInfo.getWidth(), imageInfo.getHeight(), 
                                ImageFormat.CP_PAF_BGR24, oneFace, CmFeature);
                if (rtn !=  0) {
                        playSound(250);
                        return;
                }
                
                //是否刚刚识别过
                int rfe = 0;
                int dSimilScore = 0;
        FaceSimilar faceSimilar = new FaceSimilar();
                for(int n=0;n<HowOldAreU.aryFFTime.size();n++) {
                rtn = HowOldAreU.faceEngine.compareFaceFeature(CmFeature, (FaceFeature) HowOldAreU.FaceFeature.get(n), faceSimilar);
                        if (rtn != 0) {
                                return;
                        }
                        //得分
                        dSimilScore = new BigDecimal(faceSimilar.getScore()).multiply(new BigDecimal("100")).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
                        //大于阀值
                        if(dSimilScore >= scoreThreshold){
                                if(MyFunc.datetimeSub(HowOldAreU.aryFFTime.get(n).toString(), nowTime) < recoFreq) {
                                        rfe = 1;
                                        int hdt = Integer.parseInt( HowOldAreU.aryFFCnt.get(n).toString() );
                                        if(hdt >= 1 && hdt <= 3) {
                                                playSound(180+hdt);
                                                HowOldAreU.aryFFCnt.set(n, hdt+1 );
                                                //停顿一下
                                                try {
                                                        Thread.sleep(3000);
                                                } catch(InterruptedException ex) {
                                                        Thread.currentThread().interrupt();
                                                }
                                        }
                                        break;
                                }
                        }
                }
                //最近识别过
                if(rfe == 1) {return;}
                
                //识别过10个人后,做一次自我介绍
                if(HowOldAreU.faceCnt == 11) {
                        HowOldAreU.faceCnt = 0;
                }
                if(HowOldAreU.faceCnt == 0) {
                        playSound(150);
                        HowOldAreU.faceCnt ++;
                }
                //停顿一下
                try {
                        Thread.sleep(1000);
                } catch(InterruptedException ex) {
                        Thread.currentThread().interrupt();
                }
                
                //原型
        faceInfoList.add(oneFace);
                rtn = HowOldAreU.faceEngine.process(imageInfo.getRgbData(), imageInfo.getWidth(), imageInfo.getHeight(), 
                        ImageFormat.CP_PAF_BGR24, faceInfoList, 
                        FunctionConfiguration.builder().supportAge(true).supportFace3dAngle(true).supportGender(true).build());
                if (rtn !=  0) {
                        playSound(250);
                        return;
                }

        //3D信息提取
        List<Face3DAngle> face3DAngleList = new ArrayList<Face3DAngle>();
        rtn = HowOldAreU.faceEngine.getFace3DAngle(face3DAngleList);
                if (rtn !=  0) {
                        playSound(250);
                        return;
                }
                if(face3DAngleList.size() == 0) {
                        playSound(250);
                        return;
                }
                
                //0: 正常,其他数值:检测结果不可信
                int status3d = face3DAngleList.get(0).getStatus();
                if(status3d != 0) {return;}
                BigDecimal pitch = new BigDecimal("0");
                BigDecimal roll = new BigDecimal("0");
                BigDecimal yaw = new BigDecimal("0");
                BigDecimal yes3db = new BigDecimal("0").subtract(yes3d);
                
                //俯仰角
                pitch = new BigDecimal(face3DAngleList.get(0).getPitch()).setScale(7, BigDecimal.ROUND_HALF_UP);
                if(pitch.compareTo(yes3d) == 1) {
                        playSound(301);
                        return;
                }
                if(pitch.compareTo(yes3db) == -1) {
                        playSound(302);
                        return;
                }
                //横滚角
                roll = new BigDecimal(face3DAngleList.get(0).getRoll()).setScale(7, BigDecimal.ROUND_HALF_UP);
                if(roll.compareTo(yes3d) == 1) {
                        playSound(311);
                        return;
                }
                if(roll.compareTo(yes3db) == -1) {
                        playSound(312);
                        return;
                }
                
                //偏航角
                yaw = new BigDecimal(face3DAngleList.get(0).getYaw()).setScale(7, BigDecimal.ROUND_HALF_UP);
                if(yaw.compareTo(yes3d) == 1) {
                        playSound(321);
                        return;
                }
                if(yaw.compareTo(yes3db) == -1) {
                        playSound(322);
                        return;
                }

        //年龄提取
        List<AgeInfo> ageInfoList = new ArrayList<AgeInfo>();
        rtn = HowOldAreU.faceEngine.getAge(ageInfoList);
                if (rtn !=  0) {
                        playSoundSexAge(-1,-1);
                        return;
                }
                age = ageInfoList.get(0).getAge();
                if(age > 120) {age = 120;}
                
        //性别提取
        List<GenderInfo> genderInfoList = new ArrayList<GenderInfo>();
        rtn = HowOldAreU.faceEngine.getGender(genderInfoList);
                if (rtn !=  0) {
                        playSoundSexAge(-1,age);
                        return;
                }
                sex = genderInfoList.get(0).getGender();

                //
                if(sex == -1 && age == -1) {
                        playSound(360);
                        return;
                }
                
                //播报
                playSoundSexAge(sex,age);
                
                //记录人脸,防止重复识别同一个人
                HowOldAreU.FaceFeature.add(CmFeature);
                HowOldAreU.aryFFTime.add(nowTime);
                HowOldAreU.aryFFCnt.add("1");

                //记录已识别数量
                HowOldAreU.faceCnt ++;
                //System.out.println(HowOldAreU.faceCnt+" "+now_time);
        }

        public static void playSoundSexAge(int sex,int age) {                
                //不同年龄段,不同称谓
                String agename = "frend";
                if(sex >= 0) {
                        if(age >= 0 && age <= 2) {
                                agename = "00-"+sex;
                        }else if(age >= 3 && age <= 18) {
                                agename = "03-"+sex;
                        }else if(age >= 19 && age <= 45) {
                                agename = "19-"+sex;
                        }else if(age >= 46 && age <= 75) {
                                agename = "46-"+sex;
                        }else if(age >= 76 && age <= 120) {
                                agename = "76-"+sex;
                        }
                }
                SoundPlay.playSoundFile(HowOldAreU.soundDir+"agename"+HowOldAreU.fs+"agename-"+agename+".mp3", null);
                
                //推测用语
                JSONArray ary = new JSONArray();
                ary.add("401");//你,大概
                ary.add("402");//我猜你
                ary.add("403");//我估计你
                ary.add("404");//我看你
                ary.add("405");//你看起来
                int cnt = ary.size();
                //随机选择一个
                int idx = 0;
                if(cnt > 1) {
                        Random random = new Random();
                idx = random.nextInt(cnt)%(cnt+1);
                }
                SoundPlay.playSoundFile(HowOldAreU.soundDir+ary.get(idx)+".mp3", null);

                //年龄
                SoundPlay.playSoundFile(HowOldAreU.soundDir+"age"+HowOldAreU.fs+"age"+age+".mp3", null);
                
                //停顿一下
                try {
                        Thread.sleep(1000);
                } catch(InterruptedException ex) {
                        Thread.currentThread().interrupt();
                }
                                
                //确认
                ary = new JSONArray();
                ary.add("481");//对不对啊?
                ary.add("482");//是不是呢?
                ary.add("483");//准吗?
                ary.add("484");//差不多吗?
                ary.add("485");//靠谱吧?
                cnt = ary.size();
                idx = 0;
                if(cnt > 1) {
                        Random random = new Random();
                idx = random.nextInt(cnt)%(cnt+1);
                }
                SoundPlay.playSoundFile(HowOldAreU.soundDir+ary.get(idx)+".mp3", null);
                
                //停顿一下
                try {
                        Thread.sleep(2000);
                } catch(InterruptedException ex) {
                        Thread.currentThread().interrupt();
                }
                                
                //笑一个
                ary = new JSONArray();
                ary.add("501");//哈哈!
                ary.add("502");//嘻嘻!
                cnt = ary.size();
                idx = 0;
                if(cnt > 1) {
                        Random random = new Random();
                idx = random.nextInt(cnt)%(cnt+1);
                }
                SoundPlay.playSoundFile(HowOldAreU.soundDir+ary.get(idx)+".mp3", null);
                
                //如果错了
                ary = new JSONArray();
                ary.add("521");//如果我说错了,
                ary.add("522");//要是我没有说对,
                cnt = ary.size();
                idx = 0;
                if(cnt > 1) {
                        Random random = new Random();
                    idx = random.nextInt(cnt)%(cnt+1);
                }
                SoundPlay.playSoundFile(HowOldAreU.soundDir+ary.get(idx)+".mp3", null);
                
                //别生气
                ary = new JSONArray();
                ary.add("541");//你可别生气哦!
                ary.add("542");//你别往心里去啊!
                ary.add("543");//你千万别介意哈!
                cnt = ary.size();
                idx = 0;
                if(cnt > 1) {
                        Random random = new Random();
                    idx = random.nextInt(cnt)%(cnt+1);
                }
                SoundPlay.playSoundFile(HowOldAreU.soundDir+ary.get(idx)+".mp3", null);
                
                //停顿一下
                try {
                        Thread.sleep(2000);
                } catch(InterruptedException ex) {
                        Thread.currentThread().interrupt();
                }
                
                //下一个
                ary = new JSONArray();
                ary.add("561");//来,下一个!
                ary.add("562");//请下一位朋友!
                ary.add("563");//下一位,谁来?
                cnt = ary.size();
                idx = 0;
                if(cnt > 1) {
                        Random random = new Random();
                    idx = random.nextInt(cnt)%(cnt+1);
                }
                SoundPlay.playSoundFile(HowOldAreU.soundDir+ary.get(idx)+".mp3", null);
        }
        
        public static void playSound(int sound_kind) {
                //  http://ai.baidu.com/tech/speech/tts
                JSONArray ary = new JSONArray();
                //文件集
                switch(sound_kind) {
                case 100:                        
                        ary.add("101");//秋语已经启动,就要工作啦!
                        break;

                case 150:
                        //大家好,我是机器人。主人给我取名:秋语,他还帮我训练了一双火眼金睛,
                        //看一眼就能识别出你们人类的性别和年龄。有人想过来试一试吗?
                        ary.add("150");
                        break;
                        
                case 181:                        
                        ary.add("181");//你来过的,一分钟之后再来,好吗?
                        break;
                case 182:                        
                        ary.add("182");//你来过的,一分钟之后再来,好吗?
                        break;
                case 183:                        
                        ary.add("183");//你怎么还来呀?跟你说了等一分钟的!你真是个急性子,不理你了。
                        break;
                        
                case 200: //没有发现人脸时                        
                        ary.add("201");//怎么没有人来跟我玩儿?                        
                        ary.add("202");//有人吗?快来和我玩啦!                        
                        ary.add("203");//我知道你几岁了,过来试试吧!                        
                        ary.add("204");//你们人呢?都到哪儿去了?        
                        ary.add("205");//我等了老半天,怎么连个人影也没看到!
                        break;
                        
                case 250: //看不请人脸或无法提取脸纹时                        
                        ary.add("251");//嗨!靠近一点儿,我想看看你呢!
                        ary.add("252");//喂!过来一点嘛,我都看不清你!                        
                        ary.add("253");//hello,离我近一点儿,会有惊喜的!
                        break;
                        
                        //3D角度过大
                case 301://俯仰角过大:请低一下头!
                case 302://俯仰角过大:把头抬一下!
                case 311://横滚角过大:头向左转一下!
                case 312://横滚角过大:向右转一下头!
                case 321://偏航角过大:脖子向左歪一下!
                case 322://偏航角过大:向右歪一下脖子!
                        ary.add(sound_kind);
                        break;
                        
                case 360: //性别、年龄均未知                        
                        ary.add("361");//你太神秘了,我实在猜不出你几岁!                        
                        ary.add("362");//你到底几岁呢?我绞尽脑汁也想不出来!                        
                        ary.add("363");//我无法识别你的年龄,我要请主人继续进化我。
                        break;
                }
                int cnt = ary.size();
                if(cnt == 0) {return;}
                //随机选择一个
                int idx = 0;
                if(cnt > 1) {
                        Random random = new Random();
                idx = random.nextInt(cnt)%(cnt+1);
                }
                //播放
                SoundPlay.playSoundFile(HowOldAreU.soundDir+ary.get(idx)+".mp3", null);
        }
        
        public static String initEngine() {
                JSONObject parm = MyFunc.GetAllProperties("config/parm.properties");
                String s = MyFunc.strTrim(parm.getString("err"));
                if(!"".equals(s)) {return "参数文件读取失败。"+s;        }                
                //APPID
                String APPID = MyFunc.strTrim(parm.getString("APP_ID"));
                if("".equals(APPID)){return "终端APPID缺失,程序将终止。";}
                //SDKKEY
                String WIN_SDKKEY = MyFunc.strTrim(parm.getString("WIN_SDKKEY"));
                String LIN_SDKKEY = MyFunc.strTrim(parm.getString("LIN_SDKKEY"));
                String SDKKEY = WIN_SDKKEY;
                if(!Platform.isWindows()) {SDKKEY = LIN_SDKKEY;}                
                if("".equals(SDKKEY)){return "终端SDKKEY缺失,程序将终止。";}
                
                //加载动态库
                s = FaceAbout.loadDllSo();
                if(!"".equals(s)) {
                        return "动态库加载失败,程序将终止。"+s;
                }
                //人脸引擎初始化
                try {
                        HowOldAreU.faceEngine = FaceAbout.initFaceEngine(APPID, SDKKEY);
                } catch (IOException e) {
                        return "人脸引擎初始化失败,程序将终止。"+e;
                }
                return "";
        }
        
}

分类:

技术点:

相关文章: