最近需要做一个Android的在线人脸识别项目,需求是能够在线人脸识别登录,找了很多资料都是价格很高或者是离线保存样本的,最后选择免费的虹软人脸识别,经过查询很多资料,最终完结了该项目需求,现在把它分享出来,希望能够帮助到大家学习。
提示:以下是本篇文章正文内容,下面案例可供参考
有了解过Android端虹软SDK的都知道,识别样本必须要先注册在本地,进行离线识别,这可能不符合大部分的需求,更多的可能是需要Android端在线识别。该系统使用虹软Java端第三方jar包,实现Android端人脸在线识别登录与注册功能。
客户端分为注册和登录。注册时调用相机拍照,将回调的图片信息进行bas64格式发送至服务器。登录时调用相机采集视频信息,将图片信息压缩转化后实时发送至服务端登录匹配。
1、注册拍照代码如下(示例):
/***
* 拍照
* @param view
*/
public void photograph(View view) {
loadingDialog = new LoadingDialog(RegisterCameraActivity.this,"正在获取照片...", R.drawable.icon_logo);
loadingDialog.show();
mCamera.takePicture(null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] bytes, Camera camera) {
File sdRoot = Environment.getExternalStorageDirectory();
String dir = "/Camera/";
String resultPath = sdRoot + dir + "IMG_Register.jpg";
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes,0,bytes.length);
Bitmap bitmap1 = adjustPhotoRotation(bitmap, 270);
Imageutils.saveImage(bitmap1);
if(bitmap != null){
bitmapCompress(resultPath);
}else {
camera.stopPreview();
camera.release();
dismissLoading();
}
}
});
}
2、上传图片信息代码如下(示例):
/***
* 上传图片
*/
buttonc.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
showLoading();
File sdRoot = Environment.getExternalStorageDirectory();
String dir = "/Camera/";
String resultPath = sdRoot + dir + "IMG_Register.jpg";
String resultChangePath = sdRoot + dir + "IMG_Register_change.jpg";
File file = new File(resultChangePath);
File resultPathFile = new File(resultPath);
if(!file.exists()){
dismissLoading();
return;
}
String ImgBase = Imageutils.imgTodata(resultChangePath);
HashMap<String, String> params = new HashMap<>();
String url = HttpUtils.FACE_ADD;
params.put("file", ImgBase);
params.put("username", username);
HttpUtils.sendRequestToServer(url, params, new Callback() {
@Override
public void onFailure(Request request, IOException e) {
}
@Override
public void onResponse(Response response) throws IOException {
String string = response.body().string();
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(string);
int code = jsonObject.optInt("code");
if(code == 14){
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(RegisterCameraActivity.this,"注册失败,未检出到人脸",Toast.LENGTH_SHORT).show();
}
});
}else if(code == 0){
if(file.exists()){
file.delete();
}
if(resultPathFile.exists()){
resultPathFile.delete();
}
if (loadingDialog != null){
loadingDialog.dismiss();
}
Intent it = new Intent(RegisterCameraActivity.this, SelectActivity.class);
startActivity(it);
finish();
}else {
String message = jsonObject.optString("message");
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(RegisterCameraActivity.this,message,Toast.LENGTH_SHORT).show();
}
});
}
if (loadingDialog != null){
loadingDialog.dismiss();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
});
Toast.makeText(RegisterCameraActivity.this,"请正视屏幕不要晃动",Toast.LENGTH_SHORT).show();
}
登录Activity需要实现Camera.PreviewCallback接口,实现回调中的onPreviewFrame()方法进行视频流的采集。将采集到的流数据转化为图片格式,经过压缩处理后转化为bas64格式发送服务器进行匹配,必要时在这里可以使用线程池机制来增加效率。
采集图片信息并上传代码如下(示例):
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
String timeName = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date())
.toString();
String fileName = "IMG_"+ timeName + ".jpg";
File sdRoot = Environment.getExternalStorageDirectory();
String dir = "/Camera/";
File mkDir = new File(sdRoot, dir);
if (!mkDir.exists())
mkDir.mkdirs();
File pictureFile = new File(sdRoot, dir + fileName);
if (!pictureFile.exists()) {
try {
pictureFile.createNewFile();
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = parameters.getPreviewSize();
YuvImage image = new YuvImage(data,
parameters.getPreviewFormat(), size.width, size.height,
null);
FileOutputStream filecon = new FileOutputStream(pictureFile);
image.compressToJpeg(new Rect(0, 0, image.getWidth(), image.getHeight()),
90, filecon);
String path = pictureFile.getPath();
Bitmap imageBitmap = BitmapFactory.decodeFile(path);
Bitmap bitmap1 = adjustPhotoRotation(imageBitmap, 270);
Imageutils.saveLoginImage(bitmap1,timeName);
String fileLoginName = "IMG_Login_" + timeName + ".jpg";
String resultChangePath = sdRoot + dir + fileLoginName;
bitmapCompress(resultChangePath);/*新增压缩*/
String ImgBase = Imageutils.imgTodata(resultChangePath);
//开始上传
ImgBase = ImgBase.replaceAll("[\\s*\t\n\r]", "");
//上传
HashMap<String, String> params = new HashMap<>();
params.put("file", ImgBase);
uploadImage(params,camera);
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务端使用Java语言编写,首先部署第三方jar包,配置好appid和key值。服务端接收到客户端传递过来的图片数据进行匹配,如果是注册,将图片信息保存至数据库,如果是登录,则查询数据库进行匹配。
服务器获取客户端发送图片信息处理代码如下(示例):
/**
* 人脸识别
*/
@ApiOperation(value="人脸识别", notes="待识别图像为base64格式字符串、必须指定人脸分组id")
@RequestMapping(value = "/faceSearch", method = RequestMethod.POST)
@ResponseBody
public Result<FaceSearchResDto> faceSearch(@ApiParam(value = "人脸图像数据", required = true)@RequestParam("file") String file) throws Exception {
if (groupId == null) {
return Results.newFailedResult("groupId is null");
}
byte[] decode = Base64.decode(base64Process(file));
BufferedImage bufImage = ImageIO.read(new ByteArrayInputStream(decode));
ImageInfo imageInfo = ImageFactory.bufferedImage2ImageInfo(bufImage);
//人脸特征获取
byte[] bytes = faceEngineService.extractFaceFeature(imageInfo);
if (bytes == null) {
return Results.newFailedResult(ErrorCodeEnum.NO_FACE_DETECTED);
}
//人脸比对,获取比对结果
List<FaceUserInfo> userFaceInfoList = faceEngineService.compareFaceFeature(bytes, groupId);
if (CollectionUtil.isNotEmpty(userFaceInfoList)) {
FaceUserInfo faceUserInfo = userFaceInfoList.get(0);
FaceSearchResDto faceSearchResDto = new FaceSearchResDto();
BeanUtil.copyProperties(faceUserInfo, faceSearchResDto);
List<ProcessInfo> processInfoList = faceEngineService.process(imageInfo);
if (CollectionUtil.isNotEmpty(processInfoList)) {
//人脸检测
List<FaceInfo> faceInfoList = faceEngineService.detectFaces(imageInfo);
int left = faceInfoList.get(0).getRect().getLeft();
int top = faceInfoList.get(0).getRect().getTop();
int width = faceInfoList.get(0).getRect().getRight() - left;
int height = faceInfoList.get(0).getRect().getBottom() - top;
Graphics2D graphics2D = bufImage.createGraphics();
graphics2D.setColor(Color.RED);//红色
BasicStroke stroke = new BasicStroke(5f);
graphics2D.setStroke(stroke);
graphics2D.drawRect(left, top, width, height);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ImageIO.write(bufImage, "jpg", outputStream);
byte[] bytes1 = outputStream.toByteArray();
faceSearchResDto.setImage("data:image/jpeg;base64," + Base64Utils.encodeToString(bytes1));
faceSearchResDto.setAge(processInfoList.get(0).getAge());
faceSearchResDto.setGender(processInfoList.get(0).getGender().equals(1) ? "女" : "男");
faceSearchResDto.setUsername(faceUserInfo.getUsername());
}
return Results.newSuccessResult(faceSearchResDto);
}
return Results.newFailedResult(ErrorCodeEnum.FACE_DOES_NOT_MATCH);
}
照片转化为bas64格式保存至数据库示意图
这次项目查询了很多资料,最终完成了Android人脸识别登录与注册功能,主要是使用Android端图片的压缩与转换,网络通讯,和第三方人脸识别sdk,希望能够对有需要的人有帮助。
导读语言模型给我们的生产生活带来了极大便利,但同时不少人也利用他们从事作弊工作。如何规避这些难辨真伪的文字所产生的负面影响也成为一大难题。在3月9日智源Live第33期活动「DetectGPT:判断文本是否为机器生成的工具」中,主讲人Eric为我们讲解了DetectGPT工作背后的思路——一种基于概率曲率检测的用于检测模型生成文本的工具,它可以帮助我们更好地分辨文章的来源和可信度,对保护信息真实、防止欺诈等方面具有重要意义。本次报告主要围绕其功能,实现和效果等展开。(文末点击“阅读原文”,查看活动回放。)Ericmitchell斯坦福大学计算机系四年级博士生,由ChelseaFinn和Chri
电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。 准备工作: 1、U盘一个(尽量使用8G以上的U盘)。 2、一台正常联网可使用的电脑。 3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。 4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。 U盘启动盘制作步骤: 注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注
在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList()Obt
之前说过10之后的版本没有3dScan了,所以还是9.8的版本或者之前更早的版本。 3d物体扫描需要先下载扫描的APK进行扫面。首先要在手机上装一个扫描程序,扫描现实中的三维物体,然后上传高通官网,在下载成UnityPackage类型让Unity能够使用这个扫描程序可以从高通官网上进行下载,是一个安卓程序。点到Tools往下滑,找到VuforiaObjectScanner下载后解压数据线连接手机,将apk文件拷入手机安装然后刚才解压文件中的Media文件夹打开,两个PDF图打印第一张A4-ObjectScanningTarget.pdf,主要是用来辅助扫描的。好了,接下来就是扫描三维物体。将瓶
Heroku支持人员告诉我,为了在我的Web应用程序中使用自定义字体(未安装在系统中,您可以在bash控制台中使用fc-list查看已安装的字体)我必须部署一个包含所有字体的.fonts文件夹里面的字体。问题是我不知道该怎么做。我的意思是,我不知道文件名是否必须遵循heroku的任何特殊模式,或者我必须在我的代码中做一些事情来考虑这种字体,或者如果我将它包含在文件夹中它是自动的......事实是,我尝试以不同的方式更改字体的文件名,但根本没有使用该字体。为了提供更多详细信息,我们使用字体的过程是将PDF转换为图像,更具体地说,使用rghostgem。并且最终图像根本不使用自定义字体。在
需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc
最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路
在我让另一个人重做我的前端UI之前,我的Rails应用程序运行平稳。我已经尝试解决此错误3天了。这是错误:Nosuchfileordirectory-identifyExtractedsource(aroundline#59):575859606162@post=Post.find(params[:id])authorize@postif@post.update_attributes(post_params)flash[:notice]="Postwasupdated."redirect_to[@topic,@post]else{"utf8"=>"✓","_method"=>"patc
因为我现在正在做一些时间测量,我想知道是否可以在不使用Benchmark类或命令行实用程序time的情况下测量用户时间或系统时间。使用Time类只显示挂钟时间,而不显示系统和用户时间,但是我正在寻找具有相同灵active的解决方案,例如time=TimeUtility.now#somecodeuser,system,real=TimeUtility.now-time原因是我有点不喜欢Benchmark,因为它不能只返回数字(编辑:我错了-它可以。请参阅下面的答案。)。当然,我可以解析输出,但感觉不对。*NIX系统的time实用程序也应该可以解决我的问题,但我想知道是否已经在Ruby中实
在Ruby中,以毫秒为单位获取自纪元(1970)以来的当前系统时间的正确方法是什么?我试过了Time.now.to_i,好像不是我想要的结果。我需要结果显示毫秒并且使用long类型,而不是float或double。 最佳答案 (Time.now.to_f*1000).to_iTime.now.to_f显示包含十进制数字的时间。要获得毫秒数,只需将时间乘以1000。 关于ruby-以毫秒为单位获取当前系统时间,我们在StackOverflow上找到一个类似的问题: