虹软人脸识别 - 采用数据库存取人脸特征数据

前几天有个朋友遇到了个问题,他在使用虹软的人脸识别引擎时,想更换一下人脸识别的存储方式,原本demo中使用的是文件的方式进行存储,而他想要通过数据库的方式进行存储。由于他刚接触Android不久,对数据库这块不甚了解,再加之听上去要存特征数据,听上去就很难的样子,可愁坏了他。其实虹软的人脸特征数据就是一个byte[],存储起来还是相当方便的。我为他写了一个demo,顺便与大家分享一下,希望能帮到有需要的人,本文将分为以下几点讲述。

  • 两种数据库存储方式
  • 封装数据库操作接口
  • ArcFaceDemo接入

一、两种数据库操作方式

方案一:使用原生数据库存储人脸特征数据

1. 建表

首先我们需要建一张表来存储特征数据,但是光存储特征数据还是不够的,不足以满足人脸识别的需要,因此我们还需要人脸姓名、人脸图片等数据。下面我创建了一个User表,以id为主键,并自增长,faceName用TEXT类型存储,把人脸图片与特征都用Blob存储。

注意:对于人脸库中人脸较多的场景,请将注册图存储至本地,数据库中仅保留文件路径,否则会占用很多内存。

public class FaceDatabaseHelper extends SQLiteOpenHelper {private static final String TAG = "FaceDatabaseHelper";public FaceDatabaseHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {super(context, name, factory, version);}@Overridepublic void onCreate(SQLiteDatabase db) {//创建Face表 ID 名字 照片 特征db.execSQL("CREATE TABLE IF NOT EXISTS Face" +"(id INTEGER PRIMARY KEY AUTOINCREMENT, faceName TEXT, facePic Blob , faceFeature Blob)");//建库成功后给出提示Log.i(TAG, "dataBase Create Success");}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
}

2. 新增人脸数据

表已经建好了,接下来就是往表中插入数据,需要注意的是,这里的最后一个参数需要传入jpeg格式的数据。

    public long addFace(String faceName, byte[] faceFeature, byte[] facePic) {//存人脸ContentValues values = new ContentValues();long index = -1;//写入表try {values.put("faceName", faceName);values.put("faceFeature", faceFeature);values.put("facePic", facePic);index = db.insert("Face", null, values);} catch (Exception e) {e.printStackTrace();}return index;}

3. 加载人脸数据

人脸数据已经成功的插入到了表中,接下来我们就需要将表内所有的数据加载到内存。

    public ArrayList<FaceEntity> selectAllFaces() {ArrayList<FaceEntity> dataList = new ArrayList<>();Cursor cursor = db.query("Face", null, null, null, null, null, null);while (cursor.moveToNext()) {FaceEntity data = new FaceEntity();int id = cursor.getInt(cursor.getColumnIndex("id"));String faceName = cursor.getString(cursor.getColumnIndex("faceName"));byte[] facePic = cursor.getBlob(cursor.getColumnIndex("facePic"));byte[] faceFeature = cursor.getBlob(cursor.getColumnIndex("faceFeature"));data.setId(id);data.setFaceName(faceName);data.setFacePic(facePic);data.setFaceFeature(faceFeature);dataList.add(data);}cursor.close();return dataList;}

4. 清空人脸数据

支持删除所有人脸或单张人脸。

public void deleteAllFace() {db.execSQL("delete from Face");
}
public void deleteFaceById(int id) {db.delete("Face", "id=?", new String[]{"" + id});
}

方案二:使用Room框架存储人脸特征数据

上面使用的是原生数据库操作接口,这边还提供一种使用Android官方推荐的Room框架操作数据库的示例。

1. 添加依赖

首先我们要在app下的build.gradle文件内添加room的依赖。

implementation 'android.arch.persistence.room:runtime:1.1.1'
annotationProcessor 'android.arch.persistence.room:compiler:1.1.1'

2. 建表

Room的数据库操作相比于原生的方式来说简单的多,只需要对实体类进行注解即可。

注意:对于人脸库中人脸较多的场景,请将注册图存储至本地,数据库中仅保留文件路径,否则会占用很多内存。


// entity声明定义,并且指定了映射数据表明
@Entity(tableName = "Face")
public class FaceEntity {// 设置主键,并且定义自增增@PrimaryKey(autoGenerate = true)public int id;// 字段映射具体的数据表字段名@ColumnInfo(name = "faceName")private String faceName;@ColumnInfo(name = "faceFeature")private byte[] faceFeature;@ColumnInfo(name = "facePic")private byte[] facePic;// getter/setter就不贴了...
}

3. 建库

每次打开数据库文件都会产生比较大的开销,所以将FaceRoomDatabase设计成单例。

//注解指定了database的表映射实体数据以及版本等信息
@Database(entities = {FaceEntity.class}, version = 1)
public abstract class FaceRoomDatabase extends RoomDatabase {//RoomDatabase提供直接访问底层数据库实现,我们通过定义抽象方法返回具体Dao//然后进行数据库增删该查的实现。public abstract FaceDao userDao();private static volatile FaceRoomDatabase instance;public static FaceRoomDatabase getInstance(Context context) {if (instance == null) {synchronized (FaceRoomDatabase.class) {if (instance == null) {instance = Room.databaseBuilder(context.getApplicationContext(), FaceRoomDatabase.class, "RoomFaceDB.db").build();}}}return instance;}
}

4. 数据库操作

基于Room框架的数据库操作较为简单,就不一一例举,统一放在一起进行说明。

@Dao
public interface FaceDao {//返回Long数据表示,插入条目的主键值(uid)@InsertLong addFace(FaceEntity user);//获取所有人脸数据@Query("SELECT * FROM Face")List<FaceEntity> getAllFace();//删除所有人脸数据@Query("DELETE FROM Face")int deleteAll();//删除指定人脸@Deleteint delete(FaceEntity user);
}

二、封装数据库操作接口

2.1 接口声明

为了代码切换更便捷,能够在代码中快速切换使用Room或直接使用SQLite进行数据库操作:

    // ROOM方式private static FaceDatabaseAccessObject dao = new RoomFaceDao();// 直接使用SQLite方式
//    private static FaceDatabaseAccessObject dao = new SQLiteFaceDao();

我们可以预先定义一套接口FaceDatabaseAccessObject

public interface FaceDatabaseAccessObject {/*** 初始化*/void init();/*** 插入一个人脸** @param userEntity 人脸信息* @return index*/long insert(FaceEntity userEntity);/*** 获取所有人脸** @return 所有人脸*/List<FaceEntity> getAll();/*** 清空所有人脸*/void clearAll();/*** 回收资源操作*/void release();
}

2.2 SQLite实现FaceDatabaseAccessObject接口

public class SQLiteFaceDao implements FaceDatabaseAccessObject {private static FaceDatabaseManager faceDataBaseManager;@Overridepublic void init() {faceDataBaseManager = new FaceDatabaseManager(ArcFaceApp.getApplication());}@Overridepublic long insert(FaceEntity userEntity) {if (faceDataBaseManager == null) {return -1;}return faceDataBaseManager.addFace(userEntity.getFaceName(), userEntity.getFaceFeature(), userEntity.getFacePic());}@Overridepublic List<FaceEntity> getAll() {if (faceDataBaseManager == null) {return null;}return faceDataBaseManager.selectAllFaces();}@Overridepublic void clearAll() {if (faceDataBaseManager == null) {return;}faceDataBaseManager.deleteAllFace();}@Overridepublic void release() {if (faceDataBaseManager == null) {return;}faceDataBaseManager.release();}
}

2.3 ROOM实现FaceDatabaseAccessObject接口

public class RoomFaceDao implements FaceDatabaseAccessObject {private static FaceDao dao;private FaceRoomDatabase appDatabase;@Overridepublic void init() {appDatabase = FaceRoomDatabase.getInstance(ArcFaceApp.getApplication());dao = appDatabase.userDao();}@Overridepublic long insert(FaceEntity userEntity) {return dao == null ? -1 : dao.addFace(userEntity);}@Overridepublic List<FaceEntity> getAll() {return dao == null ? null : dao.getAllFace();}@Overridepublic void clearAll() {if (dao == null) {return;}dao.deleteAll();}@Overridepublic void release() {if (appDatabase != null) {appDatabase.close();}}
}

三、ArcFaceDemo接入

数据库操作已经实现,接下来就要实际运用到项目中,首先是人脸注册,我们直接修改Demo中FaceServer类的register方法。

3.1 注册

// 创建一个头像的Bitmap,存放旋转结果图
Bitmap headBmp = getHeadImage(bgr24, width, height, faceInfoList.get(0).getOrient(), cropRect, ArcSoftImageFormat.BGR24);
// 录入人脸
ByteArrayOutputStream baos = new ByteArrayOutputStream();
headBmp.compress(Bitmap.CompressFormat.JPEG, 50, baos);
byte[] facePic = baos.toByteArray();FaceEntity user = new FaceEntity();
user.setFaceName(userName);
user.setFaceFeature(faceFeature.getFeatureData());
user.setFacePic(facePic);
dao.insert(user);

3.2 查询

上面我们已经完成了注册,接下来就是查询,由于Room不推荐在主线程中进行UI操作,我们新创建一个线程,将原本Demo中的initFaceList替换为initFaceListByDataBase

    private void initFaceListByDataBase() {new Thread(new Runnable() {@Overridepublic void run() {faceRegisterInfoList = new ArrayList<>();List<FaceEntity> userTableList = dao.getAll();for (FaceEntity userInfo : userTableList) {faceRegisterInfoList.add(new FaceRegisterInfo(userInfo.getFaceFeature(), userInfo.getFaceName(), userInfo.getFacePic()));}}}).start();}

3.3 删除

删除人脸同样属于IO操作,推荐放在子线程中处理。

    public int clearAllFaces(Context context) {synchronized (this) {if (context == null) {return 0;}int number = 0;if (faceRegisterInfoList != null) {number = faceRegisterInfoList.size();faceRegisterInfoList.clear();}new Thread(new Runnable() {@Overridepublic void run() {dao.clearAll();}}).start();return number;}}

3.4 显示

由于原本图片的加载模式是加载本地文件,而现在图片是直接存储在数据库的,因此需要对CompareResult进行修改,同时要对FaceSearchResultAdapter的图片加载做一些修改。

public class CompareResult {private String userName;private float similar;private int trackId;private byte[] facePic;public CompareResult(String userName, float similar) {this.userName = userName;this.similar = similar;}public CompareResult(String userName, float similar, byte[] facePic) {this.userName = userName;this.similar = similar;this.facePic = facePic;}
}
public CompareResult getTopOfFaceLib(FaceFeature faceFeature) {//......//.....if (maxSimilarIndex != -1) {//return new CompareResult(faceRegisterInfoList.get(maxSimilarIndex).getName(), maxSimilar);return new CompareResult(faceRegisterInfoList.get(maxSimilarIndex).getName(), maxSimilar, faceRegisterInfoList.get(maxSimilarIndex).getFacePic());}return null;
}

FaceSearchResultAdapter内修改注册照显示的图像加载。

@Override
public void onBindViewHolder(@NonNull CompareResultHolder holder, int position) {if (compareResultList == null) {return;}
//        File imgFile = new File(FaceServer.ROOT_PATH + File.separator + FaceServer.SAVE_IMG_DIR + File.separator + compareResultList.get(position).getUserName() + FaceServer.IMG_SUFFIX);
//        Glide.with(holder.imageView)
//                .load(imgFile)
//                .into(holder.imageView);Glide.with(holder.imageView).load(compareResultList.get(position).getFacePic()).into(holder.imageView);holder.textView.setText(compareResultList.get(position).getUserName());
}

3.5 效果

至此为止我们已经搭建好数据库,并且完成了识别界面相关的代码修改,下面是实际运行的效果。

四、附录

本文通过两种数据库操作方式介绍了人脸特征数据的存取,供大家参考,若有不对的地方,请大家指正!

如果对您有所帮助,可以为我的demo点个star!

提示:本文示例代码在使用前需先修改com.arcsoft.arcfacedemo.common.Constants.java中的APP_ID与SDK_KEY。

源码地址:https://github.com/1244975831/ArcFaceDemoDatabase

相关产品在虹软人脸识别开放平台进一步了解喔

虹软人脸识别 - 采用数据库存取人脸特征数据相关推荐

  1. vc中人脸识别数据导入mysql_虹软人脸识别 - 采用数据库存取人脸特征数据

    虹软人脸识别 - 采用数据库存取人脸特征数据 前几天有个朋友遇到了个问题,他在使用虹软的人脸识别引擎时,想更换一下人脸识别的存储方式,原本demo中使用的是文件的方式进行存储,而他想要通过数据库的方式 ...

  2. 人脸识别——MySQL数据库存储人脸特征信息解决方案

    需求描述 1.将人脸特征信息保存进MySQL数据库. 2.调用摄像头识别人脸,将待识别的人物进行识别,并实时地与数据库中的人脸特征信息进行比对,同时判断出被识别者的身份. 需求分析 1.准备 利用op ...

  3. 人脸识别——脸部属性辅助(特征融合)

    <A Deep Face Identification Network Enhanced by Facial Attributes Prediction> 2018,Fariborz Ta ...

  4. 人脸识别标注的68个特征

    人脸识别标注的68个特征.如图 图一标注从1开始,实际应从0开始到67 !!! 图一 图一 人脸识别的68个特征标注顺序. 鼻尖 30   鼻根 27   下巴 8   左眼外角 36   左眼内角 ...

  5. dlib库包的介绍与使用,opencv+dlib检测人脸框、opencv+dlib进行人脸68关键点检测,opencv+dlib实现人脸识别,dlib进行人脸特征聚类、dlib视频目标跟踪

    文章目录: 1 dlib库介绍 2 dlib人脸检测:绘制出人脸检测框 2.1 dlib人脸检测源码 2.2 opencv + dlib 人脸检测 2.3 dlib人脸检测总结 3 dlib人脸关键点 ...

  6. AI人工智能分析-人脸识别和分析(人脸检测跟踪、获取特征长度、提取用于人脸特征、比较相似度)

             AI人工智能分析-人脸识别和分析(人脸检测跟踪.获取特征长度.提取用于人脸特征.比较相似度) 人工智能(Artificial Intelligence),英文缩写为AI.它是研究.开 ...

  7. 【javaCV基于虹软人脸识别demo添加电脑摄像头人脸识别(图片保存,视频保存,摄像头显示等 )(附源码)】

    javaCV基于虹软人脸识别demo添加电脑摄像头人脸识别(图片保存,视频保存,摄像头显示等 )(附源码) 文章目录 javaCV基于虹软人脸识别demo添加电脑摄像头人脸识别(图片保存,视频保存,摄 ...

  8. 人脸识别接口_人工智能 人脸识别双目模组摄像头 活体检测的重要作用

    人脸识别,是基于人的脸部特征信息进行身份识别的一种生物识别技术.用摄像机或摄像头采集含有人脸的图像或视频流,并自动在图像中检测和跟踪人脸,进而对检测到的人脸进行脸部识别的一系列相关技术,通常也叫做人像 ...

  9. 人脸识别(5)---人脸识别技术及应用概览

    人脸识别技术及应用概览 科技的发展正在加速改变我们的生活.以前,我们购物埋单时,收银员会问"现金还是刷卡",现在,这句话则变成了"微信还是支付宝?"以前,我们上 ...

最新文章

  1. java注解的执行顺序_深入理解Spring的@Order注解和Ordered接口
  2. 通过CPAN安装Perl模块
  3. Linux 常用小技巧
  4. 解决逆向工程mapper映射文件不发布问题
  5. JAVA标识符的命名规则和规范
  6. 一个整数按照n,2n,4n,8n的顺序递增,当值大于5000时,把值按照指定顺序输出来。(递归)
  7. android开发 交换方向,Android实现去哪儿携程地址互换效果
  8. 街舞中的rolling机器人_首家!爆点!奈雪の茶、蛙小侠..开业倒计时!街舞PK…这个六一就差你来围观了...
  9. Django+Jquery+Ajax+验证码登录案例
  10. DataBseDesign工作笔记002---数据库表设计
  11. msf出现Database not connected等问题【已解决】
  12. vaex 处理海量数据_爱了爱了!0.052 秒打开 100GB 数据,这个Python开源库火爆了!...
  13. C/C++ 知识点---链表操作
  14. 知到智慧树答案2020python_2020知到智慧树大数据分析的python基础章节答案
  15. Hadoop高可用原理及环境搭建
  16. ssh-keygen的使用方法
  17. 【论文笔记】Details or Artifacts: A Locally Discriminative Learning Approach toRealistic Image Super-Reso
  18. EEPROM,NAND,NOR,QSPI FLASH的区别
  19. linux必看书籍推荐
  20. 【博客552】git auto-merge原理以及auto-merge的不同模式

热门文章

  1. 电视网与计算机网的区别是什么意思,网络电视和智能电视有什么区别 ?哪个好?...
  2. Spring boot 线程池之单线程问题
  3. 数据恢复大师免费安装教程
  4. C++输出流格式化方法
  5. spice仿真模型导入multisim注意事项
  6. BT宝塔面板免费使用专业版网站监控报表插件
  7. 指令集创始人潘爱民博士参加之江实验室“第二届智能计算创新论坛”并作报告...
  8. 编程小白的人工智能路之Gabor滤波提取掌纹特征并对比掌纹相似度(一)
  9. MindManager2020官方中文许可秘钥版免费下载思维导图软件安装使用教程
  10. 云演CTF——php4fun