一个简单的NettyEchoDemo

本博客 猫叔的博客,转载请申明出处阅读本文约 “4分钟” 适读人群:Java-Netty 初级 Echo简易通讯案例版本:netty 4.1.*申明:本文旨在重新分享讨论Netty官方相关案例,添加部分个人理解与要点解析。 这个是InChat的案例地址,里面补充了详细的注释,比起官方会容易看一点。 官方案例地址:https://netty.io/4.1/xref/io/... 正文EchoClient(客户端)EchoClientHandlerEchoServer(服务端)EchoServerHandler要点介绍SslContext官方介绍:https://netty.io/4.1/api/io/n... 公共抽象类,安全套接字协议实现充当工厂SSLEngine和SslHandler。在内部,它通过JDK SSLContext或OpenSSL 实现SSL_CTX,还有关于它的使用方式,如果你需要ssl加密的话 SslContextBuilder官方介绍:https://netty.io/4.1/api/io/n... 用于配置新SslContext以进行创建的构建器,其中包含多个方法这里就不多补充,大家可以去看看 InsecureTrustManagerFactory官方介绍:https://netty.io/4.1/api/io/n... 在TrustManagerFactory没有任何验证的情况下信任所有X.509证书的不安全因素 注意:切勿TrustManagerFactory在生产中使用它。它纯粹是出于测试目的,因此非常不安全。SelfSignedCertificate官方介绍:https://netty.io/4.1/api/io/n... 生成临时自签名证书以进行测试 注意:切勿在生产中使用此类生成的证书和私钥。它纯粹是出于测试目的,因此非常不安全。它甚至使用不安全的伪随机生成器在内部更快地生成项目源码EchoClient/** * @ClassName EchoClient * @Description 一个简单的应答通讯的实例 * @Author MySelf * @Date 2019/8/17 17:56 * @Version 1.0 **/public final class EchoClient { //判断是否加密 static final boolean SSL = System.getProperty("ssl") != null; //监听本地服务 static final String HOST = System.getProperty("host", "127.0.0.1"); //监听端口 static final int PORT = Integer.parseInt(System.getProperty("port", "8007")); //发送消息的大小,用于EchoClientHandler static final int SIZE = Integer.parseInt(System.getProperty("size", "256")); public static void main(String[] args) throws Exception { //公共抽象类,安全套接字协议实现充当工厂SSLEngine和SslHandler。在内部,它通过JDK SSLContext或OpenSSL 实现SSL_CTX final SslContext sslCtx; if (SSL){ //用于配置新SslContext以进行创建的构建器 sslCtx = SslContextBuilder.forClient() //用于验证远程端点证书的可信管理器 //InsecureTrustManagerFactory:在TrustManagerFactory没有任何验证的情况下信任所有X.509证书的不安全因素 //注:切勿TrustManagerFactory在生产中使用它。它纯粹是出于测试目的,因此非常不安全。 .trustManager(InsecureTrustManagerFactory.INSTANCE).build(); }else { sslCtx = null; } //事件循环 EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group) .channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY,true) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel sc) throws Exception { ChannelPipeline p = sc.pipeline(); //了解SslContext的用法 if (sslCtx != null){ p.addLast(sslCtx.newHandler(sc.alloc(),HOST,PORT)); } p.addLast(new EchoClientHandler()); } }); //这个sync后的代码均会执行 ChannelFuture f = b.connect(HOST,PORT).sync(); System.out.println("before-----"); //这个sync后的代码不会执行 f.channel().closeFuture().sync(); System.out.println("after-----"); }finally { group.shutdownGracefully(); } }}EchoClientHandler/** * @ClassName EchoClientHandler * @Description TODO * @Author MySelf * @Date 2019/8/17 18:06 * @Version 1.0 **/public class EchoClientHandler extends ChannelInboundHandlerAdapter { private final ByteBuf firstMessage; public EchoClientHandler(){ //获取EchoClient的SIZE //Unpooled:ByteBuf通过分配新空间或通过包装或复制现有字节数组,字节缓冲区和字符串来创建新的 firstMessage = Unpooled.buffer(EchoClient.SIZE); for (int i = 0; i < firstMessage.capacity(); i++){ firstMessage.writeByte((byte)i); } } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { ctx.writeAndFlush(firstMessage); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ctx.write(msg); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); }}EchoServer/** * @ClassName EchoServer * @Description 服务端 * @Author MySelf * @Date 2019/8/17 18:15 * @Version 1.0 **/public final class EchoServer { static final boolean SSL = System.getProperty("ssl") != null; static final int PORT = Integer.parseInt(System.getProperty("port", "8007")); public static void main(String[] args) throws Exception { final SslContext sslCtx; if (SSL){ //SelfSignedCertificate:生成临时自签名证书以进行测试 SelfSignedCertificate ssc = new SelfSignedCertificate(); sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build(); }else{ sslCtx = null; } EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); final EchoServerHandler serverHandler = new EchoServerHandler(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup,workerGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG,100) .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline p = ch.pipeline(); if (sslCtx != null){ p.addLast(sslCtx.newHandler(ch.alloc())); } p.addLast(serverHandler); } }); ChannelFuture f = b.bind(PORT).sync(); f.channel().closeFuture().sync(); }finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } }}EchoServerHandler/** * @ClassName EchoServerHandler * @Description TODO * @Author MySelf * @Date 2019/8/17 18:14 * @Version 1.0 **/@ChannelHandler.Sharablepublic class EchoServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ctx.write(msg); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); }}公众号:Java猫说学习交流群:728698035 ...

August 18, 2019 · 3 min · jiezi

【C#】虹软Arc人脸识别 ArcFace 2.0 demo

环境:win7以上 VS2013以上sdk版本:ArcFace v2.0x86 x64平台Debug、Release配置都已通过编译下载地址:https://github.com/ArcsoftEsc…配置过程:到虹软官网下载SDK2.0版本,点击下载解压下载的x86或x64的zip包,本Demo以x64为例选择平台,如:,将libarcsoft_face.dll和libarcsoft_face_engine.dll放到binx64Debug下修改工程下App.config配置文件中的APP_ID和对应的SDKKEY64的值点击启动或者F5启动;其他详细信息请阅读项目中doc目录下的说明文档;常见问题:1.后引擎初始化失败 (1)请选择对应的平台,如x64,x86 (2)删除bin下面对应的asf_install.dat,freesdk_132512.dat; (3)请确保App.config下的appid,和appkey与当前sdk一一对应。 2.SDK支持那些格式的图片人脸检测? 目前SDK支持的图片格式有jpg,jpeg,png,bmp等。 3.使用人脸检测功能对图片大小有要求吗? 推荐的图片大小最大不要超过2M,因为图片过大会使人脸检测的效率不理想,当然图片也不宜过小,否则会导致无法检测到人脸。4.使用人脸识别引擎提取到的人脸特征信息是什么? 人脸特征信息是从图片中的人脸上提取的人脸特征点,是byte[]数组格式。5.SDK人脸比对的阈值设为多少合适? 推荐值为0.8,用户可根据不同场景适当调整阈值。 6.可不可以将人脸特征信息保存起来,等需要进行人脸比对的时候直接拿保存好的人脸特征进行比对? 可以,当人脸个数比较多时推荐先存储起来,在使用时直接进行比对,这样可以大大提高比对效率。存入数据库时,请以Blob的格式进行存储,不能以string或其他格式存储。 7.在.Net项目中出现堆栈溢出问题,如何解决? .Net平台设置的默认堆栈大小为256KB,SDK中需要的大小为512KB以上,推荐调整堆栈的方法为: new Thread(new ThreadStart(delegate { ASF_MultiFaceInfo multiFaceInfo = FaceUtil.DetectFace(pEngine, imageInfo); }), 1024 * 512).Start(); 8.X86模式下批量注册人脸有内存溢出或图片空指针 请增加虚拟内存或每次批量注册人脸控制在20张图片范围内 9.图片中有人脸,但是检测时未检测到人脸 (1)请调整detectFaceScaleVal的值; (2)请确认图片的宽度是否为4的倍数; (3)请确认图片是否通过ImageUtil.ReadBMP方法进行数据调整。感谢 虹软提供免费离线的人脸识别SDK

March 14, 2019 · 1 min · jiezi

人脸识别demo开发经验

本来打算做个C#版demo,但没用成功,基于虹软的免费人脸识别技术过程如下:1、 传入一张单人脸照片;2、调用检测人脸函数ASFDetectFaces,成功返回人脸信息的指针;3、使用 Marshal.ReadByte(intPtr,offset) 函数读出字节数,发现前16个字节是人脸框范围,第28至31个字节应该是人脸角度,其他信息不太清楚。想了下,最简单的办法是用C++将动态库再封装一次。将封装后的demo及C++代码上传。demo是X86的,只识别单张人脸,有别的需求的同学可自己封装库。https://download.csdn.net/dow…

March 13, 2019 · 1 min · jiezi

ArcFace 2.0 人脸识别Android 版demo

环境要求1、运行环境 armeabi-v7a2、系统要求 Android 5.0 (API Level 21)及以上3、开发环境 Android Studio下载地址:https://github.com/ArcsoftEsc…更多信息可以去虹软人工智能开放平台查看快速上手1、在src->main目录下新建文件夹jniLibs->armeabi-v7a,将libarcsoft_face.so和libarcsoft_face_engine.so添加到src->main->jniLibs->armeabi-v7a路径下2、在app目录下新建文件夹libs,将arcsoft_face.jar放入app->libs路径下,并依赖进工程方法1:方法2:3、将官网申请sdk获取到的APP_ID和SDK_KEY填入Common->Constants.java4、运行app问题指南1、详细接入指南可见官网:http://ai.arcsoft.com.cn/manual/arcface_android_guideV2.html2、常见问题可见SDK中的doc文档ARCSOFT_ARC_FACE_DEVELOPER’S_GUIDE.pdf,或官网帮助与支持

March 12, 2019 · 1 min · jiezi

基于虹软人脸识别ArcFace 2.0 服务端Java 版Demo

源代码传送:https://github.com/itboyst/Ar…开发环境准备:开发使用到的软件和工具:Jdk8、mysql5.7、libarcsoft_face.dll(so)、libarcsoft_face_engine.dll(so)、libarcsoft_face_engine_jni.dll(so)、idea注:libarcsoft_face.dll(so)、libarcsoft_face_engine.dll(so)、libarcsoft_face_engine_jni.dll(so)、app-id、sdk-key可以到虹软官网戳这里 免费申请下载本地配置:配置环境(推荐jdk8,mysql5.7,maven3,idea)引擎库libarcsoft_face、libarcsoft_face_engine、libarcsoft_face_engine_jni。把dll或so文件拷贝到java.library.path所包含的路径下,注意区分X86和X64,和当前jdk版本一致。初始化项目 创建数据库arcsoft_face_demo,执行脚本arcsoft_face_demo.sql使用idea启动项目修改配置文件srcmainresourcesapplication.properties填写数据库地址:spring.datasource.druid.url填写数据库用户名:spring.datasource.druid.username填写数据库密码:spring.datasource.druid.password填写人脸识别id:config.freesdk.app-id填写人脸识别key:config.freesdk.sdk-key启动项目在com.arcsoft.facedemo包下,右击Application,选择Run ‘Application’项目访问地址http://127.0.0.1:8080/demo项目流程图源代码传送:https://github.com/itboyst/Ar…

March 11, 2019 · 1 min · jiezi

基于虹软ArcFace2.0 java版 利用人脸识别猜年龄的demo

首先感谢虹软,是你们提供这么好的SDK支撑了我们的想象力!这是一个用javav编写的可视化应用,用户通过自己的脸和计算机进行交互,计算机则通过萌萌女孩的语音和用户对话。核心程序就是利用ArcFace2.0识别性别、年龄,但是为了获得正面脸,会根据ArcFace2.0的人脸3D角度、用语音提醒用户,这是一个的互动环节。最后,程序会幽默的、萌萌的告诉用户他的性别、年龄。获取SDK 请戳这里完整的项目源码、可执行程序,放在百度网盘:链接: https://pan.baidu.com/s/1eHF6… 提取码: 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 “”; } }====================================FaceAbout.java====================================package app;import java.awt.color.ColorSpace;import java.awt.image.BufferedImage;import java.awt.image.ColorConvertOp;import java.awt.image.DataBufferByte;import java.io.File;import java.io.IOException;import java.util.ArrayList;import com.arcsoft.face.EngineConfiguration;import com.arcsoft.face.FaceEngine;import com.arcsoft.face.FunctionConfiguration;import com.sun.jna.Platform;import tools.FileOpe;public class FaceAbout { //加载本地库 public static String loadDllSo() { String fileType = “",s=”",s2=””; //路径 String dllPath = HowOldAreU.localPath+“ArcSoft”; //添加到系统路径 addDirToPath(dllPath); //处理依赖库 if(Platform.isWindows()) { String[] files = new String[2]; files[0] = “msvcp120.dll”; files[1] = “msvcr120.dll”; for(int i=0;i<files.length;i++) { s = dllPath+HowOldAreU.fs+files; s2 = “C:\Windows\System32\"+files; if(!new File(s2).exists()) { try { new FileOpe().copyFile(new File(s), new File(s2)); } catch (IOException e) { return “依赖库复制失败("+s+” -> “+s2+")。"+e; } } } } //文件类型 if(Platform.isWindows()) { fileType = “.dll”; }else { fileType = “.so”; } ArrayList<String> ary = new ArrayList<String>(); ary.add(“libarcsoft_face”); ary.add(“libarcsoft_face_engine”); ary.add(“libarcsoft_face_engine_jni”); //加载 for(int i=0;i<ary.size();i++) { s = dllPath+HowOldAreU.fs+ary.get(i)+fileType; try { System.load(s); }catch (Exception e) { return “动态库("+s+")加载失败。"+e; } } return “”; } //添加路径 private static void addDirToPath(String s) { try { //获取系统path变量对象 java.lang.reflect.Field field = ClassLoader.class.getDeclaredField(“sys_paths”); //设置此变量对象可访问 field.setAccessible(true); //获取此变量对象的值 String[] path = (String[])field.get(null); //是否已经存在 for(int i=0;i<path.length;i++) { if(s.equals(path)) { field.setAccessible(false); return; } } //创建字符串数组,在原来的数组长度上增加一个,用于存放增加的目录 String[] tem = new String[path.length+1]; //将原来的path变量复制到tem中 System.arraycopy(path,0,tem,0,path.length); //将增加的目录存入新的变量数组中 tem[path.length] = s; //将增加目录后的数组赋给path变量对象 field.set(null,tem); } catch (Exception e) { e.printStackTrace(); } } //初始化 public static FaceEngine initFaceEngine(String APPID, String SDKKEY) throws IOException { //初始化人脸引擎 FaceEngine faceEngine = new FaceEngine(); faceEngine.active(APPID, SDKKEY); //引擎配置 EngineConfiguration engineConfiguration = EngineConfiguration.builder().functionConfiguration( FunctionConfiguration.builder() .supportAge(true) .supportFace3dAngle(true) .supportFaceDetect(true) .supportFaceRecognition(true) .supportGender(true) .build()).build(); //初始化引擎 faceEngine.init(engineConfiguration); return faceEngine; } //错误码 public static String errCodeList(int codeNo) { String infoStr = “”; switch(codeNo) { case 0: infoStr = “成功”;break; case 1: infoStr = “错误原因不明”;break; case 2: infoStr = “无效的参数”;break; case 3: infoStr = “引擎不支持”;break; case 4: infoStr = “内存不足”;break; case 5: infoStr = “状态错误”;break; case 6: infoStr = “用户取消相关操作”;break; case 7: infoStr = “操作时间过期”;break; case 8: infoStr = “用户暂停操作”;break; case 9: infoStr = “缓冲上溢”;break; case 10: infoStr = “缓冲下溢”;break; case 11: infoStr = “存贮空间不足”;break; case 12: infoStr = “组件不存在”;break; case 13: infoStr = “全局数据不存在”;break; case 28673: infoStr = “无效的AppId”;break; case 28674: infoStr = “无效的SDKkey”;break; case 28675: infoStr = “AppId和SDKKey不匹配”;break; case 28676: infoStr = “SDKKey和使用的SDK不匹配”;break; case 28677: infoStr = “系统版本不被当前SDK所支持”;break; case 28678: infoStr = “SDK有效期过期,需要重新下载更新”;break; case 73729: infoStr = “无效的输入内存”;break; case 73730: infoStr = “无效的输入图像参数”;break; case 73731: infoStr = “无效的脸部信息”;break; case 73732: infoStr = “当前设备无GPU可用”;break; case 73733: infoStr = “待比较的两个人脸特征的版本不一致”;break; case 81921: infoStr = “人脸特征检测错误未知”;break; case 81922: infoStr = “人脸特征检测内存错误”;break; case 81923: infoStr = “人脸特征检测格式错误”;break; case 81924: infoStr = “人脸特征检测参数错误”;break; case 81925: infoStr = “人脸特征检测结果置信度低”;break; case 86017: infoStr = “Engine不支持的检测属性”;break; case 86018: infoStr = “需要检测的属性未初始化”;break; case 86019: infoStr = “待获取的属性未在process中处理过”;break; case 86020: infoStr = “ROCESS不支持的检测属性,例如FR,有自己独立的处理函数”;break; case 86021: infoStr = “无效的输入图像”;break; case 86022: infoStr = “无效的脸部信息”;break; case 90113: infoStr = “SDK激活失败,请打开读写权限”;break; case 90114: infoStr = “SDK已激活”;break; case 90115: infoStr = “SDK未激活”;break; case 90116: infoStr = “detectFaceScaleVal不支持”;break; case 90117: infoStr = “SDK版本不匹配”;break; case 90118: infoStr = “设备不匹配”;break; case 90119: infoStr = “唯一标识不匹配”;break; case 90120: infoStr = “参数为空”;break; case 90121: infoStr = “活体检测功能已过期”;break; case 90122: infoStr = “版本不支持”;break; case 90123: infoStr = “签名错误”;break; case 90124: infoStr = “数据库插入错误”;break; case 90125: infoStr = “唯一标识符校验失败”;break; case 90126: infoStr = “颜色空间不支持”;break; case 90127: infoStr = “图片宽度或高度不支持”;break; case 90128: infoStr = “android.permission.READ_PHONE_STATE权限被拒绝”;break; case 90129: infoStr = “激活数据被破坏,请删除激活文件,重新进行激活”;break; case 94209: infoStr = “无法解析主机地址”;break; case 94210: infoStr = “无法连接服务器”;break; case 94211: infoStr = “网络连接超时”;break; case 94212: infoStr = “网络未知错误”;break; case 98305: infoStr = “无法连接激活码服务器”;break; case 98306: infoStr = “服务器系统错误”;break; case 98307: infoStr = “请求参数错误”;break; case 98308: infoStr = “激活码正确,且未被使用,但和传入的APPID及APPKEY不匹配”;break; case 98309: infoStr = “传入的KEY值虽然正确,但此KEY已经被激活”;break; case 98310: infoStr = “KEY格式不对,一般来说是KEY错误或者未传入KEY值”;break; } return infoStr; } // public ImageInfo bufferedImage2ImageInfo(BufferedImage image) { ImageInfo imageInfo = new ImageInfo(); int width = image.getWidth(); int height = image.getHeight(); // 使图片居中 width = width & (~3); height = height & (~3); imageInfo.width = width; imageInfo.height = height; //根据原图片信息新建一个图片缓冲区 BufferedImage resultImage = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR); //得到原图的rgb像素矩阵 int[] rgb = image.getRGB(0, 0, width, height, null, 0, width); //将像素矩阵 绘制到新的图片缓冲区中 resultImage.setRGB(0, 0, width, height, rgb, 0, width); //进行数据格式化为可用数据 BufferedImage dstImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_3BYTE_BGR); if (resultImage.getType() != BufferedImage.TYPE_3BYTE_BGR) { ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB); ColorConvertOp colorConvertOp = new ColorConvertOp(cs, dstImage.createGraphics().getRenderingHints()); colorConvertOp.filter(resultImage, dstImage); } else { dstImage = resultImage; } //获取rgb数据 imageInfo.rgbData = ((DataBufferByte) (dstImage.getRaster().getDataBuffer())).getData(); return imageInfo; } // public class ImageInfo { public byte[] rgbData; public int width; public int height; public byte[] getRgbData() { return rgbData; } public void setRgbData(byte[] rgbData) { this.rgbData = rgbData; } public int getWidth() { return width; } public void setWidth(int width) { this.width = width; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } }}==============程序在Windows7 64位 可以运行起来。里面调用摄像头的包,链接:https://github.com/sarxos/web…程序之中的不当之处,还请社区的技术专家和各位同仁批评指正,谢谢。 ...

March 7, 2019 · 10 min · jiezi

虹软2.0 python3+ 人脸识别 demo

python3+虹软2.0的所有功能整合测试完成,并对虹软所有功能进行了封装,现提供demo主要功能,1.人脸识别2.人脸特征提取3.特征比对4.特征数据存储与比对其他特征没有添加face_class.py复制代码from ctypes import #人脸框class MRECT(Structure): fields=[(u’left1’,c_int32),(u’top1’,c_int32),(u’right1’,c_int32),(u’bottom1’,c_int32)]#版本信息 版本号,构建日期,版权说明class ASF_VERSION(Structure): fields=[(‘Version’,c_char_p),(‘BuildDate’,c_char_p),(‘CopyRight’,c_char_p)]#单人人脸信息 人脸狂,人脸角度class ASF_SingleFaceInfo(Structure): fields=[(‘faceRect’,MRECT),(‘faceOrient’,c_int32)]#多人人脸信息 人脸框数组,人脸角度数组,人脸数class ASF_MultiFaceInfo(Structure): # fields=[(‘faceRect’,POINTER(MRECT)),(‘faceOrient’,POINTER( c_int32)),(‘faceNum’,c_int32)] fields=[(u’faceRect’,POINTER(MRECT)),(u’faceOrient’,POINTER(c_int32)),(u’faceNum’, c_int32)] # fields=[(u’faceRect’,MRECT50),(u’faceOrient’,c_int32*50),(u’faceNum’,c_int32)]#人脸特征 人脸特征,人脸特征长度class ASF_FaceFeature(Structure): fields=[(‘feature’,c_void_p),(‘featureSize’,c_int32)]#自定义图片类class IM: def init(self): self.filepath=None self.date=None self.width=0 self.height=0复制代码face_dll.py复制代码from ctypes import *from face_class import *wuyongdll=CDLL(’d:\python\Test\Face\lib\X64\libarcsoft_face.dll’)dll=CDLL(’d:\python\Test\Face\lib\X64\libarcsoft_face_engine.dll’)dllc=cdll.msvcrtASF_DETECT_MODE_VIDEO = 0x00000000ASF_DETECT_MODE_IMAGE = 0xFFFFFFFFc_ubyte_p = POINTER(c_ubyte) #激活jihuo=dll.ASFActivationjihuo.restype = c_int32jihuo.argtypes = (c_char_p,c_char_p)#初始化chushihua=dll.ASFInitEnginechushihua.restype=c_int32chushihua.argtypes=(c_long,c_int32,c_int32,c_int32,c_int32,POINTER(c_void_p))#人脸识别shibie=dll.ASFDetectFacesshibie.restype=c_int32shibie.argtypes=(c_void_p,c_int32,c_int32,c_int32,POINTER(c_ubyte),POINTER(ASF_MultiFaceInfo))#特征提取tezheng=dll.ASFFaceFeatureExtracttezheng.restype=c_int32tezheng.argtypes=(c_void_p,c_int32,c_int32,c_int32,POINTER(c_ubyte),POINTER(ASF_SingleFaceInfo),POINTER(ASF_FaceFeature))#特征比对bidui=dll.ASFFaceFeatureComparebidui.restype=c_int32bidui.argtypes=(c_void_p,POINTER(ASF_FaceFeature),POINTER(ASF_FaceFeature),POINTER(c_float))malloc = dllc.mallocfree = dllc.freememcpy = dllc.memcpymalloc.restype = c_void_pmalloc.argtypes = (c_size_t, )free.restype = Nonefree.argtypes = (c_void_p, )memcpy.restype = c_void_pmemcpy.argtypes = (c_void_p, c_void_p, c_size_t)复制代码face_function.py复制代码import face_dll,face_classfrom ctypes import import cv2from io import BytesIO# from Main import Handle=c_void_p()c_ubyte_p = POINTER(c_ubyte) # 激活函数def JH(appkey,sdkey): ret=face_dll.jihuo(appkey,sdkey) return ret# 初始化函数def CSH():# 1:视频或图片模式,2角度,3最小人脸尺寸推荐16,4最多人脸数最大50,5功能,6返回激活句柄 ret=face_dll.chushihua(0xFFFFFFFF,0x1,16,50,5,byref(Handle)) # Main.Handle=Handle return ret,Handle# cv2记载图片并处理def LoadImg(im): img=cv2.imread(im.filepath) sp=img.shape img=cv2.resize(img,(sp[1]//44,sp[0]//44)) sp=img.shape im.data=img im.width=sp[1] im.height=sp[0] return imdef RLSB(im): faces=face_class.ASF_MultiFaceInfo() img=im.data imgby=bytes(im.data) imgcuby=cast(imgby,c_ubyte_p) ret=face_dll.shibie(Handle,im.width,im.height,0x201,imgcuby,byref(faces)) return ret,faces# 显示人脸识别图片def showimg(im,faces): for i in range(0,faces.faceNum): ra=faces.faceRect[i] cv2.rectangle(im.data,(ra.left1,ra.top1),(ra.right1,ra.bottom1),(255,0,0,),2) cv2.imshow(‘faces’,im.data) cv2.waitKey(0)#提取人脸特征def RLTZ(im,ft): detectedFaces=face_class.ASF_FaceFeature() img=im.data imgby=bytes(im.data) imgcuby=cast(imgby,c_ubyte_p) ret=face_dll.tezheng(Handle,im.width,im.height,0x201,imgcuby,ft,byref(detectedFaces)) if ret==0: retz=face_class.ASF_FaceFeature() retz.featureSize=detectedFaces.featureSize #必须操作内存来保留特征值,因为c++会在过程结束后自动释放内存 retz.feature=face_dll.malloc(detectedFaces.featureSize) face_dll.memcpy(retz.feature,detectedFaces.feature,detectedFaces.featureSize) # print(‘提取特征成功:’,detectedFaces.featureSize,mem) return ret,retz else: return ret#特征值比对,返回比对结果def BD(tz1,tz2): jg=c_float() ret=face_dll.bidui(Handle,tz1,tz2,byref(jg)) return ret,jg.value#单人特征写入文件def writeFTFile(feature,filepath): f = BytesIO(string_at(feature.feature,feature.featureSize)) a=open(filepath,‘wb’) a.write(f.getvalue()) a.close()#从多人中提取单人数据def getsingleface(singleface,index): ft=face_class.ASF_SingleFaceInfo() ra=singleface.faceRect[index] ft.faceRect.left1=ra.left1 ft.faceRect.right1=ra.right1 ft.faceRect.top1=ra.top1 ft.faceRect.bottom1=ra.bottom1 ft.faceOrient=singleface.faceOrient[index] return ft#从文件获取特征值def ftfromfile(filepath): fas=face_class.ASF_FaceFeature() f=open(’d:/1.dat’,‘rb’) b=f.read() f.close() fas.featureSize=b.len() fas.feature=face_dll.malloc(fas.featureSize) face_dll.memcpy(fas.feature,b,fas.featureSize) return fas复制代码Main1.py复制代码import face_dll,face_classfrom ctypes import *import cv2import face_function as funAppkey=b’‘SDKey=b’’# 激活ret=fun.JH(Appkey,SDKey)if ret==0 or ret==90114: print(‘激活成功:’,ret)else: print(‘激活失败:’,ret) pass# 初始化ret=fun.CSH()if ret[0]==0: print(‘初始化成功:’,ret,‘句柄’,fun.Handle)else: print(‘初始化失败:’,ret)# 加载图片im=face_class.IM()im.filepath=‘e:/2.jpg’im=fun.LoadImg(im)print(im.filepath,im.width,im.height)# cv2.imshow(‘im’,im.data)# cv2.waitKey(0)print(‘加载图片完成:’,im)ret=fun.RLSB(im)if ret[0]==-1: print(‘人脸识别失败:’,ret) passelse: print(‘人脸识别成功:’,ret)# 显示人脸照片# showimg(im,ret)#提取单人1特征ft=fun.getsingleface(ret[1],0)tz1=fun.RLTZ(im,ft)[1]#提取单人2特征ft=fun.getsingleface(ret[1],1)tz2=fun.RLTZ(im,ft)[1]#特征保存到文件# fun.writeFTFile(tz1,’d:/1.dat’)# fun.writeFTFile(tz2,’d:/2.dat’)#文件获取特征tz=fun.ftfromfile(’d:/1.dat’)jg=fun.BD(tz1,tz)print(jg[1])#结果比对# jg=fun.BD(tz1,tz2)# print(jg[1])复制代码 ...

March 6, 2019 · 1 min · jiezi