├── .gitignore ├── .idea ├── .name ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── gradle.xml ├── misc.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── Screenshots ├── 1.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── 7.png ├── ats.png └── so.png ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── seetaface2demo │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── seetaface2demo │ │ │ ├── CompareActivity.kt │ │ │ ├── CompareAdapter.kt │ │ │ ├── FaceBean.kt │ │ │ ├── FaceRecognizer2Activity.kt │ │ │ └── MainActivity.kt │ ├── jniLibs │ │ └── armeabi-v7a │ │ │ ├── libFaceDetectorJni.so │ │ │ ├── libFaceRecognizerJni.so │ │ │ ├── libPointDetectorJni.so │ │ │ └── libholiday.so │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_compare.xml │ │ ├── activity_facerecognizer2.xml │ │ ├── activity_main.xml │ │ └── item_compare_rv.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── cwt.jpg │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ ├── ly.jpg │ │ ├── lyf.jpg │ │ ├── lyf2.jpg │ │ ├── lyf_1.jpg │ │ ├── lyf_2.jpg │ │ ├── lyf_3.jpeg │ │ ├── lyf_4.jpeg │ │ ├── lyf_5.jpg │ │ ├── lyf_6.jpg │ │ ├── lyf_7.jpeg │ │ ├── lyf_8.jpg │ │ ├── lyf_9.jpg │ │ ├── lzy.jpg │ │ ├── wyf.jpg │ │ ├── zly.jpg │ │ ├── zyl0.jpeg │ │ ├── zyl1.jpg │ │ ├── zyl2.jpg │ │ ├── zyl3.jpg │ │ ├── zyl4.jpeg │ │ ├── zyl5.jpg │ │ └── zyl6.jpg │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── example │ └── seetaface2demo │ └── ExampleUnitTest.kt ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── liseetaface2 ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── seeta │ │ └── sdk │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── seeta │ │ │ └── sdk │ │ │ ├── FaceDetector2.java │ │ │ ├── FaceRecognizer2.java │ │ │ ├── PointDetector2.java │ │ │ ├── SeetaImageData.java │ │ │ ├── SeetaPointF.java │ │ │ ├── SeetaRect.java │ │ │ └── util │ │ │ ├── SeetaHelper.java │ │ │ └── SeetaUtil.java │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── seeta │ └── sdk │ └── ExampleUnitTest.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | SeetaFace2Demo -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | xmlns:android 17 | 18 | ^$ 19 | 20 | 21 | 22 |
23 |
24 | 25 | 26 | 27 | xmlns:.* 28 | 29 | ^$ 30 | 31 | 32 | BY_NAME 33 | 34 |
35 |
36 | 37 | 38 | 39 | .*:id 40 | 41 | http://schemas.android.com/apk/res/android 42 | 43 | 44 | 45 |
46 |
47 | 48 | 49 | 50 | .*:name 51 | 52 | http://schemas.android.com/apk/res/android 53 | 54 | 55 | 56 |
57 |
58 | 59 | 60 | 61 | name 62 | 63 | ^$ 64 | 65 | 66 | 67 |
68 |
69 | 70 | 71 | 72 | style 73 | 74 | ^$ 75 | 76 | 77 | 78 |
79 |
80 | 81 | 82 | 83 | .* 84 | 85 | ^$ 86 | 87 | 88 | BY_NAME 89 | 90 |
91 |
92 | 93 | 94 | 95 | .* 96 | 97 | http://schemas.android.com/apk/res/android 98 | 99 | 100 | ANDROID_ATTRIBUTE_ORDER 101 | 102 |
103 |
104 | 105 | 106 | 107 | .* 108 | 109 | .* 110 | 111 | 112 | BY_NAME 113 | 114 |
115 |
116 |
117 |
118 | 119 | 121 |
122 |
-------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LiSeetaFace2 2 | 离线人脸识别升级版SeetaFace2 3 | 4 | ###### 效果截图 5 | 1. 人脸检测识别 6 |
7 | 8 | 9 | 10 |
11 | 2. 人脸相似度: 12 |
13 | 14 | 15 |
16 |
17 | 18 | 19 |
20 | 21 | 22 | ### 使用 23 | + 一、How to use ? 24 | 25 | Step 1. Add it in your root build.gradle at the end of repositories: 26 | ``` 27 | allprojects { 28 | repositories { 29 | ... 30 | maven { url 'https://jitpack.io' } 31 | } 32 | } 33 | ``` 34 | Step 2. Add the dependency 35 | ``` 36 | dependencies { 37 | implementation 'com.github.shuguoli68:LiSeetaFace2:1.0' 38 | } 39 | ``` 40 | 41 | 42 | + 二、添加so文件、将模型文件复制到SD卡 43 | 44 | 1. **so文件下载**:https://pan.baidu.com/s/1lG56H7GXuQDfC6ybhrXbNA 45 | armeabi-v7a: libSeetaFaceDetector2.so 、 libSeetaFaceLandmarker2.so 、 libSeetaFaceRecognizer2.so 、 libseetanet2.so 46 | 将SO文件放置在jniLibs下的armeabi-v7a的文件夹下,并且在主module下(一般为app): 47 | ``` 48 | defaultConfig { 49 | ... 50 | ndk { 51 | abiFilters 'armeabi-v7a' 52 | } 53 | } 54 | ``` 55 |
56 | 57 |
58 | 59 | 2. **模型文件下载**: https://pan.baidu.com/s/1s4OWPnVFj3_xLNoQM1mdqA 60 | dat模型文件seetaface :SeetaFaceDetector2.0.ats 、 SeetaFaceRecognizer2.0.ats 、 SeetaPointDetector2.0.pts5.ats 61 | 将三个ats文件放置在SD卡,根目录下的seetaface目录下,可以放在assets资源目录下,然后复制到SD卡,或者去服务器下载 62 |
63 | 64 |
65 | 66 | + 二、初始化代码 67 | ``` 68 | Thread{ 69 | if (SeetaHelper.copyAts(this))//将assets目录中的模型文件拷贝到SD卡 70 | SeetaHelper.getInstance().init() 71 | }.start() 72 | ``` 73 | 74 | + 三、关键代码 75 | ``` 76 | val seetaImageData = SeetaUtil.ConvertToSeetaImageData(bitmap)//转化SeetaImageData 77 | val seetaRects = SeetaHelper.getInstance().faceDetector2.Detect(seetaImageData)//人脸框的位置 78 | val seetaPoints = SeetaHelper.getInstance().pointDetector2.Detect(seetaImageData, seetaRects[i])//脸部5个特征点 79 | //得出两张人脸的相似度 80 | val sim = SeetaHelper.getInstance().faceRecognizer2.Compare( 81 | seetaImageData, 82 | seetaPoints, 83 | seetaImageData2, 84 | seetaPoints2 85 | ) 86 | ``` 87 | 如有需求,也可以重新设置模型文件所在目录,必须初始化前设置。如: 88 | ``` 89 | //设置模型文件在SD卡的位置 90 | SeetaHelper.ROOT_CACHE = Environment.getExternalStorageDirectory().toString() + File.separator + "seetaface" 91 | //设置assets目录中的模型文件 92 | SeetaHelper.ROOT_ASSETS = "seetaface" 93 | ``` 94 | 95 | 96 | > 参考: 97 | >> https://github.com/seetafaceengine/SeetaFace2 98 | >> https://github.com/seetaface/SeetaFaceEngine2/blob/master/example/android/README.md 99 | -------------------------------------------------------------------------------- /Screenshots/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/Screenshots/1.png -------------------------------------------------------------------------------- /Screenshots/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/Screenshots/2.png -------------------------------------------------------------------------------- /Screenshots/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/Screenshots/3.png -------------------------------------------------------------------------------- /Screenshots/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/Screenshots/4.png -------------------------------------------------------------------------------- /Screenshots/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/Screenshots/5.png -------------------------------------------------------------------------------- /Screenshots/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/Screenshots/6.png -------------------------------------------------------------------------------- /Screenshots/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/Screenshots/7.png -------------------------------------------------------------------------------- /Screenshots/ats.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/Screenshots/ats.png -------------------------------------------------------------------------------- /Screenshots/so.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/Screenshots/so.png -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | apply plugin: 'kotlin-android' 4 | 5 | apply plugin: 'kotlin-android-extensions' 6 | 7 | android { 8 | compileSdkVersion 28 9 | buildToolsVersion "29.0.1" 10 | defaultConfig { 11 | applicationId "com.example.seetaface2demo" 12 | minSdkVersion 21 13 | targetSdkVersion 28 14 | versionCode 1 15 | versionName "1.0" 16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 17 | ndk { 18 | abiFilters 'armeabi-v7a' 19 | } 20 | } 21 | buildTypes { 22 | release { 23 | minifyEnabled false 24 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 25 | } 26 | } 27 | compileOptions { 28 | sourceCompatibility = 1.8 29 | targetCompatibility = 1.8 30 | } 31 | } 32 | 33 | //kotlin { 34 | // experimental { 35 | // coroutines 'enable' 36 | // } 37 | //} 38 | 39 | dependencies { 40 | implementation fileTree(dir: 'libs', include: ['*.jar']) 41 | implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 42 | implementation 'androidx.appcompat:appcompat:1.1.0' 43 | implementation 'androidx.core:core-ktx:1.1.0' 44 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 45 | testImplementation 'junit:junit:4.12' 46 | androidTestImplementation 'androidx.test:runner:1.2.0' 47 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 48 | 49 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2" 50 | // implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1" 51 | implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.2.4' 52 | implementation project(path: ':liseetaface2') 53 | } 54 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/seetaface2demo/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.example.seetaface2demo 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.example.seetaface2demo", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 27 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/seetaface2demo/CompareActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.seetaface2demo 2 | 3 | import android.graphics.Bitmap 4 | import android.graphics.BitmapFactory 5 | import android.os.Bundle 6 | import android.os.Handler 7 | import android.os.Message 8 | import android.util.Log 9 | import android.widget.Toast 10 | import androidx.appcompat.app.AppCompatActivity 11 | import androidx.recyclerview.widget.LinearLayoutManager 12 | import com.seeta.sdk.SeetaImageData 13 | import com.seeta.sdk.SeetaPointF 14 | import com.seeta.sdk.SeetaRect 15 | import com.seeta.sdk.util.SeetaHelper 16 | import com.seeta.sdk.util.SeetaUtil 17 | import kotlinx.android.synthetic.main.activity_compare.* 18 | import kotlinx.coroutines.* 19 | import java.lang.ref.WeakReference 20 | 21 | class CompareActivity : AppCompatActivity(){ 22 | 23 | private lateinit var data: List 24 | private lateinit var adapter: CompareAdapter 25 | 26 | lateinit var seetaImageData: SeetaImageData 27 | lateinit var seetaPoints: Array 28 | 29 | private val mHandler = MyHandler(this) 30 | 31 | 32 | override fun onCreate(savedInstanceState: Bundle?) { 33 | super.onCreate(savedInstanceState) 34 | setContentView(R.layout.activity_compare) 35 | initData() 36 | initTarget() 37 | initListener() 38 | } 39 | 40 | private fun initData() { 41 | data = arrayListOf( 42 | FaceBean(R.mipmap.zyl0,0.0f), 43 | FaceBean(R.mipmap.zyl1,0.0f), 44 | FaceBean(R.mipmap.zyl2,0.0f), 45 | FaceBean(R.mipmap.zyl3,0.0f), 46 | FaceBean(R.mipmap.zyl4,0.0f), 47 | FaceBean(R.mipmap.zyl5,0.0f), 48 | FaceBean(R.mipmap.zyl6,0.0f), 49 | FaceBean(R.mipmap.lyf,0.0f), 50 | FaceBean(R.mipmap.lzy,0.0f), 51 | FaceBean(R.mipmap.lyf2,0.0f) 52 | ) 53 | adapter = CompareAdapter(this, data) 54 | rv.layoutManager = LinearLayoutManager(this) 55 | rv.adapter = adapter 56 | } 57 | 58 | private fun initTarget() { 59 | val bitmap = BitmapFactory.decodeResource(resources, R.mipmap.zyl0) 60 | seetaImageData = SeetaUtil.ConvertToSeetaImageData(bitmap) 61 | val seetaRects = SeetaHelper.getInstance().faceDetector2.Detect(seetaImageData) 62 | seetaPoints = SeetaHelper.getInstance().pointDetector2.Detect(seetaImageData, seetaRects[0]) 63 | bitmap.recycle() 64 | // SeetaHelper.faceRecognizer2.Clear() 65 | // val targetId = SeetaHelper.faceRecognizer2.Register(seetaImageData, seetaPoints) 66 | // Log.i("compare", "targetId:$targetId") 67 | } 68 | 69 | private fun initListener() { 70 | btn1.setOnClickListener { 71 | Toast.makeText(this,"开始获取两张图片中人脸相似度", Toast.LENGTH_SHORT).show() 72 | btn1.isEnabled = false 73 | Thread{ 74 | compareTwo() 75 | }.start() 76 | } 77 | } 78 | 79 | private fun compareTwo() { 80 | var bitmap:Bitmap 81 | var seetaImageData2:SeetaImageData 82 | var seetaRects:Array 83 | var seetaPoints2:Array 84 | for (position in data.indices) { 85 | bitmap = BitmapFactory.decodeResource(resources, data[position].resId) 86 | seetaImageData2 = SeetaUtil.ConvertToSeetaImageData(bitmap) 87 | seetaRects = SeetaHelper.getInstance().faceDetector2.Detect(seetaImageData2) 88 | seetaPoints2 = SeetaHelper.getInstance().pointDetector2.Detect(seetaImageData2, seetaRects[0]) 89 | val value = SeetaHelper.getInstance().faceRecognizer2.Compare(seetaImageData,seetaPoints,seetaImageData2,seetaPoints2) 90 | data[position].value = value 91 | Log.i("compare", "value:$value") 92 | mHandler.sendMessage(mHandler.obtainMessage(1,position)) 93 | } 94 | } 95 | 96 | private inner class MyHandler(comAct:CompareActivity):Handler(){ 97 | var act:WeakReference = WeakReference(comAct) 98 | override fun handleMessage(msg: Message?) { 99 | super.handleMessage(msg) 100 | val main = act.get() 101 | if (msg?.what == 1){ 102 | main?.adapter?.notifyItemChanged(msg?.obj as Int) 103 | if (main?.data?.size?.minus(1) ?: 0 == msg?.obj as Int) 104 | btn1.isEnabled = true 105 | } 106 | } 107 | } 108 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/seetaface2demo/CompareAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.example.seetaface2demo 2 | 3 | import android.content.Context 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import android.widget.ImageView 8 | import android.widget.TextView 9 | import androidx.recyclerview.widget.RecyclerView 10 | 11 | class CompareAdapter(private val mContext: Context, private val data:List) : RecyclerView.Adapter() { 12 | 13 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CompareHolder { 14 | return CompareHolder(LayoutInflater.from(mContext).inflate(R.layout.item_compare_rv, parent, false)) 15 | } 16 | 17 | override fun getItemCount(): Int { 18 | return data.size 19 | } 20 | 21 | override fun onBindViewHolder(holder: CompareHolder, position: Int) { 22 | val img = holder.itemView.findViewById(R.id.item_img) 23 | val txt = holder.itemView.findViewById(R.id.item_txt) 24 | img.setImageResource(data[position].resId) 25 | txt.text = "相似度:${data[position].value}" 26 | } 27 | 28 | inner class CompareHolder(itemView:View):RecyclerView.ViewHolder(itemView) 29 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/seetaface2demo/FaceBean.kt: -------------------------------------------------------------------------------- 1 | package com.example.seetaface2demo 2 | 3 | import android.graphics.Bitmap 4 | 5 | data class FaceBean( 6 | var resId: Int, 7 | var value:Float 8 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/example/seetaface2demo/FaceRecognizer2Activity.kt: -------------------------------------------------------------------------------- 1 | package com.example.seetaface2demo 2 | 3 | import android.app.Activity 4 | import android.app.ProgressDialog 5 | import android.graphics.* 6 | import android.os.Bundle 7 | import android.util.Log 8 | import android.view.View 9 | import androidx.appcompat.app.AppCompatActivity 10 | import com.luck.picture.lib.PictureSelector 11 | import com.luck.picture.lib.config.PictureMimeType 12 | import com.seeta.sdk.SeetaImageData 13 | import com.seeta.sdk.SeetaRect 14 | import com.seeta.sdk.util.SeetaHelper 15 | import com.seeta.sdk.util.SeetaUtil 16 | import kotlinx.android.synthetic.main.activity_facerecognizer2.* 17 | import android.content.Intent 18 | import android.widget.Toast 19 | import kotlinx.coroutines.Dispatchers 20 | import kotlinx.coroutines.GlobalScope 21 | import kotlinx.coroutines.async 22 | import kotlinx.coroutines.launch 23 | 24 | //人脸检测、关键点定位、两张人脸相似度 25 | class FaceRecognizer2Activity : AppCompatActivity() , View.OnClickListener{ 26 | 27 | 28 | lateinit var paint:Paint 29 | lateinit var bitmap: Bitmap 30 | lateinit var bitmap2: Bitmap 31 | lateinit var seetaImageData: SeetaImageData 32 | lateinit var seetaRects:Array 33 | var hasFace = false 34 | val similarity = mutableListOf() 35 | lateinit var pd:ProgressDialog 36 | 37 | override fun onCreate(savedInstanceState: Bundle?) { 38 | super.onCreate(savedInstanceState) 39 | setContentView(R.layout.activity_facerecognizer2) 40 | bitmap = BitmapFactory.decodeResource(resources, R.mipmap.lyf2) 41 | bitmap2 = BitmapFactory.decodeResource(resources, R.mipmap.lyf) 42 | initData() 43 | pd = ProgressDialog(this) 44 | pd.setTitle("提示") 45 | pd.setMessage("正在检测中...") 46 | pd.setCanceledOnTouchOutside(false) 47 | } 48 | 49 | private fun initData() { 50 | bitmap = BitmapFactory.decodeResource(resources, R.mipmap.lyf2) 51 | detectFace() 52 | paint = Paint(Paint.ANTI_ALIAS_FLAG) 53 | paint.style = Paint.Style.STROKE 54 | paint.strokeWidth = 3.0f 55 | paint.color = Color.RED 56 | paint.textSize = 36.0f 57 | } 58 | 59 | private fun detectFace(){ 60 | Thread{ 61 | seetaImageData = SeetaUtil.ConvertToSeetaImageData(bitmap) 62 | seetaRects = SeetaHelper.getInstance().faceDetector2.Detect(seetaImageData) 63 | if (seetaRects.isEmpty()) { 64 | Log.i("detectFace","没有检测到人脸") 65 | hasFace = false 66 | } 67 | hasFace = true 68 | }.start() 69 | } 70 | 71 | override fun onClick(p0: View?) { 72 | when(p0?.id){ 73 | R.id.btn1 -> { 74 | PictureSelector.create(this) 75 | .openGallery(PictureMimeType.ofImage()) 76 | .maxSelectNum(1) 77 | .forResult(1); 78 | } 79 | R.id.btn2 -> { 80 | if (!hasFace){ 81 | Toast.makeText(this, "没有检测到人脸", Toast.LENGTH_SHORT).show() 82 | return 83 | } 84 | val out =bitmap.copy(Bitmap.Config.ARGB_8888, true) 85 | val canvas = Canvas(out) 86 | //绘制出所有的检测出来的人脸的区域 87 | for (i in seetaRects.indices){ 88 | val rect = seetaRects[i] 89 | canvas.drawRect(Rect(rect.x, rect.y, rect.x+rect.width, rect.y+rect.height), paint) 90 | canvas.drawText(i.toString(), rect.x + rect.width/2.0f, rect.y-15.0f, paint) 91 | } 92 | img1.setImageBitmap(out) 93 | } 94 | R.id.btn3 -> { 95 | if (!hasFace){ 96 | Toast.makeText(this, "没有检测到人脸", Toast.LENGTH_SHORT).show() 97 | return 98 | } 99 | val out = bitmap.copy(Bitmap.Config.ARGB_8888, true) 100 | val canvas = Canvas(out) 101 | for (i in seetaRects.indices) { 102 | val rect = seetaRects[i] 103 | canvas.drawText(i.toString(), rect.x + rect.width/2.0f, rect.y-15.0f, paint) 104 | //根据检测到的人脸进行关键点定位 105 | val seetaPoints = SeetaHelper.getInstance().pointDetector2.Detect(seetaImageData, rect) 106 | if (seetaPoints.isNotEmpty()) { 107 | paint.color = Color.RED 108 | for (seetaPoint in seetaPoints) { //绘制面部关键点 109 | canvas.drawCircle( 110 | seetaPoint.x.toFloat(), 111 | seetaPoint.y.toFloat(), 112 | 5.0f, 113 | paint 114 | ) 115 | } 116 | } 117 | } 118 | img1.setImageBitmap(out) 119 | } 120 | R.id.btn4 -> { 121 | PictureSelector.create(this) 122 | .openGallery(PictureMimeType.ofImage()) 123 | .maxSelectNum(1) 124 | .forResult(2); 125 | } 126 | R.id.btn5 -> { 127 | compareTwo() 128 | } 129 | } 130 | } 131 | 132 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { 133 | super.onActivityResult(requestCode, resultCode, data) 134 | if (resultCode == Activity.RESULT_OK) { 135 | when (requestCode) { 136 | 1 -> { 137 | // 图片、视频、音频选择结果回调 138 | val selectList = PictureSelector.obtainMultipleResult(data) 139 | bitmap = BitmapFactory.decodeFile(selectList[0].path) 140 | img1.setImageBitmap(bitmap) 141 | detectFace() 142 | } 143 | 2 -> { 144 | val selectList = PictureSelector.obtainMultipleResult(data) 145 | bitmap2 = BitmapFactory.decodeFile(selectList[0].path) 146 | img2.setImageBitmap(bitmap2) 147 | } 148 | } 149 | } 150 | } 151 | 152 | 153 | private fun compareTwo() { 154 | txt.text = "相似度(与第一张图片第0张人脸):" 155 | if (seetaRects.isEmpty()){ 156 | Toast.makeText(this@FaceRecognizer2Activity, "第一张图片没有检测到人脸", Toast.LENGTH_SHORT).show() 157 | return 158 | } 159 | similarity.clear() 160 | val seetaImageData2 = SeetaUtil.ConvertToSeetaImageData(bitmap2) 161 | val seetaRects2 = SeetaHelper.getInstance().faceDetector2.Detect(seetaImageData2) 162 | if (seetaRects2.isEmpty()){ 163 | Toast.makeText(this@FaceRecognizer2Activity, "第二张图片没有检测到人脸", Toast.LENGTH_SHORT).show() 164 | return 165 | } 166 | showDia() 167 | val out = bitmap2.copy(Bitmap.Config.ARGB_8888, true) 168 | val result = StringBuffer() 169 | val compare = GlobalScope.async (Dispatchers.IO) { 170 | val canvas = Canvas(out) 171 | //绘制出所有的检测出来的人脸的区域 172 | for (i in seetaRects2.indices) { 173 | val rect = seetaRects2[i] 174 | canvas.drawRect(Rect(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height), paint) 175 | canvas.drawText(i.toString(), rect.x + rect.width/2.0f, rect.y-15.0f, paint) 176 | //根据检测到的人脸进行面部关键点定位 177 | val seetaPoints = SeetaHelper.getInstance().pointDetector2.Detect(seetaImageData, seetaRects[0])//第一张人脸 178 | val seetaPoints2 = SeetaHelper.getInstance().pointDetector2.Detect(seetaImageData2, rect) 179 | val sim = SeetaHelper.getInstance().faceRecognizer2.Compare( 180 | seetaImageData, 181 | seetaPoints, 182 | seetaImageData2, 183 | seetaPoints2 184 | ) 185 | Log.i("FaceRecognizer2", "similarity:${sim}") 186 | similarity.add(sim) 187 | } 188 | for (i in similarity.indices) { 189 | if (!result.isNullOrBlank()) 190 | result.append(";\n") 191 | result.append("第$i 个:${similarity[i]}") 192 | Log.i("FaceRecognizer2", "第$i 个similarity:${similarity[i]}") 193 | } 194 | } 195 | GlobalScope.launch (Dispatchers.Main){ 196 | compare.await() 197 | txt.text = "相似度(与第一张图片第0张人脸):\n $result" 198 | img2.setImageBitmap(out) 199 | cancelDia() 200 | } 201 | } 202 | 203 | private fun showDia(){ 204 | if (pd!=null && !pd.isShowing){ 205 | pd.show() 206 | } 207 | } 208 | 209 | private fun cancelDia(){ 210 | if (pd!=null && pd.isShowing){ 211 | pd.dismiss() 212 | } 213 | } 214 | 215 | override fun onDestroy() { 216 | super.onDestroy() 217 | cancelDia() 218 | } 219 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/seetaface2demo/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.seetaface2demo 2 | 3 | import android.Manifest 4 | import android.app.Activity 5 | import android.content.Intent 6 | import android.content.pm.PackageManager 7 | import android.os.Build 8 | import androidx.appcompat.app.AppCompatActivity 9 | import android.os.Bundle 10 | import android.os.Environment 11 | import android.provider.Settings 12 | import android.text.Editable 13 | import android.text.TextUtils 14 | import android.text.TextWatcher 15 | import android.text.style.BackgroundColorSpan 16 | import android.util.Log 17 | import android.view.View 18 | import android.widget.Toast 19 | import androidx.annotation.NonNull 20 | import androidx.core.app.ActivityCompat 21 | import androidx.core.content.ContextCompat 22 | import androidx.core.content.ContextCompat.startActivity 23 | import com.seeta.sdk.util.SeetaHelper 24 | import com.seeta.sdk.util.SeetaUtil 25 | import kotlinx.android.synthetic.main.activity_main.* 26 | import kotlinx.coroutines.* 27 | import java.io.File 28 | import kotlin.concurrent.thread 29 | 30 | class MainActivity : AppCompatActivity(),View.OnClickListener { 31 | 32 | //权限 33 | val pers = arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE) 34 | 35 | override fun onCreate(savedInstanceState: Bundle?) { 36 | super.onCreate(savedInstanceState) 37 | setContentView(R.layout.activity_main) 38 | initPer() 39 | } 40 | 41 | private fun initPer() { 42 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 43 | //判断是否具有权限 44 | for (per in pers) { 45 | if (ContextCompat.checkSelfPermission(this, per) != PackageManager.PERMISSION_GRANTED) { 46 | ActivityCompat.requestPermissions(this, arrayOf(per), 1) 47 | }else{ 48 | initData() 49 | } 50 | } 51 | } 52 | } 53 | 54 | override fun onRequestPermissionsResult(requestCode: Int, @NonNull permissions: Array, @NonNull grantResults: IntArray) { 55 | if (requestCode == 1) { 56 | if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 57 | initData() 58 | } else { 59 | Toast.makeText(this,"需要访问SD卡权限,否则无法使用",Toast.LENGTH_SHORT).show() 60 | } 61 | } else { 62 | super.onRequestPermissionsResult(requestCode, permissions, grantResults) 63 | } 64 | } 65 | 66 | private fun initData() { 67 | // SeetaHelper.ROOT_CACHE = Environment.getExternalStorageDirectory().toString() + File.separator + "seetaface" 68 | // SeetaHelper.ROOT_ASSETS = "seetaface" 69 | Thread{ 70 | if (SeetaHelper.copyAts(this)) 71 | SeetaHelper.getInstance().init() 72 | }.start() 73 | 74 | } 75 | 76 | override fun onClick(p0: View?) { 77 | var clz:Class<*> = FaceRecognizer2Activity::class.java 78 | when(p0?.id){ 79 | R.id.main_txt2 -> { 80 | clz = CompareActivity::class.java 81 | } 82 | } 83 | startActivity(Intent(this@MainActivity, clz)) 84 | } 85 | 86 | override fun onDestroy() { 87 | super.onDestroy() 88 | SeetaHelper.getInstance().destroy() 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi-v7a/libFaceDetectorJni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/jniLibs/armeabi-v7a/libFaceDetectorJni.so -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi-v7a/libFaceRecognizerJni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/jniLibs/armeabi-v7a/libFaceRecognizerJni.so -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi-v7a/libPointDetectorJni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/jniLibs/armeabi-v7a/libPointDetectorJni.so -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi-v7a/libholiday.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/jniLibs/armeabi-v7a/libholiday.so -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_compare.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 12 | 20 | 31 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_facerecognizer2.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 11 | 18 | 23 | 36 | 49 | 62 | 63 | 70 | 79 | 84 | 97 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 22 | 23 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_compare_rv.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 15 | 24 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/cwt.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/cwt.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ly.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/ly.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/lyf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/lyf.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/lyf2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/lyf2.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/lyf_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/lyf_1.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/lyf_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/lyf_2.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/lyf_3.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/lyf_3.jpeg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/lyf_4.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/lyf_4.jpeg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/lyf_5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/lyf_5.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/lyf_6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/lyf_6.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/lyf_7.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/lyf_7.jpeg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/lyf_8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/lyf_8.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/lyf_9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/lyf_9.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/lzy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/lzy.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/wyf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/wyf.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/zly.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/zly.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/zyl0.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/zyl0.jpeg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/zyl1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/zyl1.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/zyl2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/zyl2.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/zyl3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/zyl3.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/zyl4.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/zyl4.jpeg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/zyl5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/zyl5.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/zyl6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/app/src/main/res/mipmap-xxxhdpi/zyl6.jpg -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | SeetaFace2Demo 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/com/example/seetaface2demo/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.example.seetaface2demo 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext.kotlin_version = '1.3.41' 5 | repositories { 6 | google() 7 | jcenter() 8 | 9 | } 10 | dependencies { 11 | classpath 'com.android.tools.build:gradle:3.5.0' 12 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | allprojects { 19 | repositories { 20 | google() 21 | jcenter() 22 | maven { url "https://jitpack.io" } 23 | } 24 | } 25 | 26 | task clean(type: Delete) { 27 | delete rootProject.buildDir 28 | } 29 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official 22 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Sep 29 21:11:18 CST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /liseetaface2/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /liseetaface2/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 28 5 | buildToolsVersion "29.0.1" 6 | 7 | 8 | defaultConfig { 9 | minSdkVersion 21 10 | targetSdkVersion 28 11 | versionCode 1 12 | versionName "1.0" 13 | 14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 15 | consumerProguardFiles 'consumer-rules.pro' 16 | } 17 | 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | 25 | } 26 | 27 | dependencies { 28 | implementation fileTree(dir: 'libs', include: ['*.jar']) 29 | 30 | implementation 'androidx.appcompat:appcompat:1.1.0' 31 | testImplementation 'junit:junit:4.12' 32 | androidTestImplementation 'androidx.test:runner:1.2.0' 33 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 34 | } 35 | -------------------------------------------------------------------------------- /liseetaface2/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuguoli68/LiSeetaFace2/ec1246ee5e69e2c8728dae30ddcf81928ea27e99/liseetaface2/consumer-rules.pro -------------------------------------------------------------------------------- /liseetaface2/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /liseetaface2/src/androidTest/java/com/seeta/sdk/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.seeta.sdk; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 24 | 25 | assertEquals("com.seeta.sdk.test", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /liseetaface2/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /liseetaface2/src/main/java/com/seeta/sdk/FaceDetector2.java: -------------------------------------------------------------------------------- 1 | package com.seeta.sdk; 2 | 3 | 4 | public class FaceDetector2 5 | { 6 | static { 7 | System.loadLibrary("FaceDetectorJni"); 8 | } 9 | 10 | public long impl = 0; 11 | 12 | private native void construct(String model); 13 | public native void dispose(); 14 | 15 | /** 16 | * \brief construct an facedetector 17 | * \param model model path 18 | * facerecognizer的构造方法 19 | * 参数:模型路径 20 | */ 21 | public FaceDetector2(String model) { 22 | this.construct(model); 23 | } 24 | 25 | 26 | protected void finalize() throws Throwable { 27 | super.finalize(); 28 | this.dispose(); 29 | } 30 | 31 | /** 32 | * \brief detect faces 33 | * \param image [in] 34 | * \return an array of rectangle, contains each faces location 35 | * \note return 0 length array if no face detected 36 | * \note faces were sorted by width * length 37 | * 检测面孔 38 | * 参数:img 39 | * 返回矩形数组,包含每个面的位置 40 | * 如果未检测到脸部,则返回0长度数组 41 | * 注意:面的位置按宽度*长度排序 42 | */ 43 | public native SeetaRect[] Detect(SeetaImageData img); 44 | 45 | } 46 | -------------------------------------------------------------------------------- /liseetaface2/src/main/java/com/seeta/sdk/FaceRecognizer2.java: -------------------------------------------------------------------------------- 1 | package com.seeta.sdk; 2 | 3 | 4 | public class FaceRecognizer2 5 | { 6 | static { 7 | System.loadLibrary("FaceRecognizerJni"); 8 | } 9 | 10 | public long impl = 0; 11 | 12 | private native void construct(String model); 13 | public native void dispose(); 14 | 15 | public FaceRecognizer2() { 16 | this(""); 17 | } 18 | 19 | /** 20 | * \brief construct an facerecognizer 21 | * \param model model path 22 | * facerecognizer的构造方法 23 | * 参数:模型路径 24 | */ 25 | public FaceRecognizer2(String model) { 26 | this.construct(model); 27 | } 28 | 29 | protected void finalize() throws Throwable { 30 | super.finalize(); 31 | this.dispose(); 32 | } 33 | 34 | /** 35 | * \brief return similarity of two faces 36 | * \param image1 [in] the original image of face1 37 | * \param landmarks1 [in] the detected landmarks of face1 38 | * \param image2 [in] the original image of face2 39 | * \param landmarks2 [in] the detected landmarks of face2 40 | * \return return similarity of face1 and face2 41 | * \note the detected landmarks must have number of PointDetector2::LandmarkNum 42 | * \note return 0 if failed 43 | * 返回两张脸的相似度 44 | * 参数image1:face1的原始图像 45 | * 参数landmarks1:face1的特征点 46 | * 参数image2:face2的原始图像 47 | * 参数landmarks2:face2的特征点 48 | * 返回face1和face2的相似度 49 | * 请注意,检测到的关键点必须具有PointDetector2 :: LandmarkNum的数量 50 | * 注意如果失败则返回0 51 | */ 52 | public native float Compare(SeetaImageData image1, SeetaPointF[] landmarks1, 53 | SeetaImageData image2, SeetaPointF[] landmarks2); 54 | 55 | /** 56 | * \brief register faces to database, return the index of registered face 57 | * \param image [in] the original image of face 58 | * \param landmarks [in] the detected landmarks of face 59 | * \return index of registered face 60 | * \note the detected landmarks must have number of PointDetector2::LandmarkNum 61 | * \note return -1 if faild. 62 | * 向数据库注册面孔,返回已注册面孔的索引 63 | * 参数image:人脸的原始图像 64 | * 参数landmarks:检测到的面部关键点 65 | * 返回已注册面孔的索引 66 | * 请注意,检测到的面部关键点必须具有PointDetector2 :: LandmarkNum的数量 67 | * 如果失败,请返回-1。 68 | */ 69 | public native int Register(SeetaImageData image, SeetaPointF[] landmarks); 70 | 71 | /** 72 | * \brief clear all registered face 73 | * 清除所有已注册的面孔 74 | */ 75 | public native void Clear(); 76 | 77 | /** 78 | * \brief get the number of registerd faces 79 | * \return the number of registerd faces 80 | * 获取已注册面孔的数量 81 | * 返回已注册面孔的数量 82 | */ 83 | public native int MaxRegisterIndex(); 84 | 85 | /** 86 | * \brief recognize the given face from database, return the most similar face's index 87 | * \param image [in] the original image of face 88 | * \param landmarks [in] the detected landmarks of face 89 | * \param similarity [out] the most similarity , note similarity must be one length array of float 90 | * \return the most similar face's index 91 | * \note return -1 if faild. 92 | * \sa Register 93 | * 从数据库中识别出给定的面孔,返回最相似的面孔的索引 94 | * 参数image:人脸的原始图像 95 | * 参数landmarks:检测到的面部地标中 96 | * 参数similarity:最相似值,请注意相似度必须是float的长度为1的数组 97 | * 返回最相似的面孔的索引 98 | * 如果失败,请返回-1。 99 | * sa注册 100 | */ 101 | public native int Recognize(SeetaImageData image, SeetaPointF[] landmarks, float[] similarity); 102 | 103 | /** 104 | * \brief recognize the given face from database, return each similarity of database 105 | * \param image [in] the original image of face 106 | * \param landmarks [in] the detected landmarks of face 107 | * \return an array of similarity, with length MaxRegisterIndex 108 | * \note using index returned by Register to get exact face's similarity 109 | * \sa Register 110 | * \sa MaxRegisterIndex 111 | * 从数据库中识别出给定的面孔,返回数据库的每个相似性 112 | * 参数image:人脸的原始图像 113 | * 参数landmarks:检测到的面部地标中 114 | * 返回长度为MaxRegisterIndex的相似度数组 115 | * 注意使用Register返回的索引来获得确切的面孔相似度 116 | * sa 注册 117 | * sa MaxRegisterIndex 118 | */ 119 | public native float[] RecognizeEx(SeetaImageData image, SeetaPointF[] landmarks); 120 | 121 | } 122 | -------------------------------------------------------------------------------- /liseetaface2/src/main/java/com/seeta/sdk/PointDetector2.java: -------------------------------------------------------------------------------- 1 | package com.seeta.sdk; 2 | 3 | public class PointDetector2 4 | { 5 | static { 6 | System.loadLibrary("PointDetectorJni"); 7 | } 8 | public long impl = 0; 9 | 10 | private native void construct(String model); 11 | public native void dispose(); 12 | 13 | /** 14 | * \brief construct an pointdetector 15 | * \param model model path 16 | * pointdetector的构造方法 17 | * 参数:模型路径 18 | */ 19 | public PointDetector2(String model) { 20 | this.construct(model); 21 | } 22 | 23 | protected void finalize() throws Throwable { 24 | super.finalize(); 25 | this.dispose(); 26 | } 27 | 28 | /** 29 | * \brief get number of landmarks can be detected 30 | * \return number of landmarks can be detected 31 | * 获取可检测到的面部关键点 32 | * 返回可以检测到面部关键点的数量 33 | */ 34 | public native int LandmarkNum(); 35 | 36 | /** 37 | * \brief detect points on face 38 | * \param image [in] the orignal image 39 | * \param face [in] detected face location 40 | * \return an array of points, contains each point location, with length of LandmarkNum 41 | * \sa LandmarkNum 42 | * 检测面部关键点 43 | * 参数image:原始图像 44 | * 参数face:检测到的脸部位置 45 | * 返回关键点的数组,包含每个关键点的位置,其长度为LandmarkNum 46 | * sa LandmarkNum 47 | */ 48 | public native SeetaPointF[] Detect(SeetaImageData image, SeetaRect face); 49 | 50 | } 51 | -------------------------------------------------------------------------------- /liseetaface2/src/main/java/com/seeta/sdk/SeetaImageData.java: -------------------------------------------------------------------------------- 1 | package com.seeta.sdk; 2 | 3 | public class SeetaImageData 4 | { 5 | public SeetaImageData(int width, int height, int channels) { 6 | this.data = new byte[width * height * channels]; 7 | this.width = width; 8 | this.height = height; 9 | this.channels = channels; 10 | } 11 | 12 | public SeetaImageData(int width, int height) { 13 | this(width, height, 1); 14 | } 15 | 16 | public byte[] data; 17 | public int width; 18 | public int height; 19 | public int channels; 20 | } 21 | -------------------------------------------------------------------------------- /liseetaface2/src/main/java/com/seeta/sdk/SeetaPointF.java: -------------------------------------------------------------------------------- 1 | package com.seeta.sdk; 2 | 3 | public class SeetaPointF 4 | { 5 | public double x; 6 | public double y; 7 | } 8 | -------------------------------------------------------------------------------- /liseetaface2/src/main/java/com/seeta/sdk/SeetaRect.java: -------------------------------------------------------------------------------- 1 | package com.seeta.sdk; 2 | 3 | public class SeetaRect 4 | { 5 | public int x; 6 | public int y; 7 | public int width; 8 | public int height; 9 | } 10 | -------------------------------------------------------------------------------- /liseetaface2/src/main/java/com/seeta/sdk/util/SeetaHelper.java: -------------------------------------------------------------------------------- 1 | package com.seeta.sdk.util; 2 | 3 | 4 | import android.content.Context; 5 | import android.os.Environment; 6 | import android.util.Log; 7 | 8 | import com.seeta.sdk.FaceDetector2; 9 | import com.seeta.sdk.FaceRecognizer2; 10 | import com.seeta.sdk.PointDetector2; 11 | 12 | import java.io.File; 13 | 14 | public class SeetaHelper { 15 | 16 | public float SIMILARITY_VALUE = 0.55f;//相似度临界值 17 | //人脸识别引擎文件 18 | public static String ROOT_CACHE = Environment.getExternalStorageDirectory() + File.separator+"seetaface"; 19 | public static String ROOT_ASSETS = "seetaface";//assets目录中要拷贝的文件名 20 | private static final String model1 = ROOT_CACHE+ File.separator + "SeetaFaceDetector2.0.ats"; 21 | private static final String model2 = ROOT_CACHE+ File.separator + "SeetaPointDetector2.0.pts5.ats"; 22 | private static final String model3 = ROOT_CACHE+ File.separator + "SeetaFaceRecognizer2.0.ats"; 23 | //人脸检测、关键点定位、特征提取与对比 24 | public FaceDetector2 faceDetector2; 25 | public PointDetector2 pointDetector2; 26 | public FaceRecognizer2 faceRecognizer2; 27 | 28 | private static SeetaHelper instance; 29 | 30 | /** 31 | * 初始化引擎 32 | * 耗时8s左右,建议放在子线程 33 | */ 34 | private SeetaHelper(){ 35 | Log.i("Seetaface", "开始引擎初始化"); 36 | if (faceDetector2!=null && pointDetector2!=null && faceRecognizer2!=null) { 37 | Log.i("Seetaface", "引擎已初始化"); 38 | return; 39 | } 40 | //人脸检测模块 41 | faceDetector2 = new FaceDetector2(model1); 42 | //面部关键点定位模块 43 | pointDetector2 = new PointDetector2(model2); 44 | //人脸特征提取与比对模块 45 | faceRecognizer2 = new FaceRecognizer2(model3); 46 | Log.i("Seetaface", "引擎初始化完成"); 47 | } 48 | 49 | 50 | public void init(){ 51 | //检测引擎文件是否存在 52 | if (!new File(ROOT_CACHE).exists() || !new File(model1).exists() || !new File(model2).exists() || !new File(model3).exists()) { 53 | Log.i("Seetaface", "初始化失败,SD卡不存在引擎文件"); 54 | }else { 55 | Log.i("Seetaface", "初始化成功"); 56 | } 57 | } 58 | 59 | public static SeetaHelper getInstance(){ 60 | if (instance == null){ 61 | synchronized (SeetaHelper.class){ 62 | if (instance == null){ 63 | instance = new SeetaHelper(); 64 | } 65 | } 66 | } 67 | return instance; 68 | } 69 | 70 | 71 | /** 72 | * 从assets中复制ats模型文件到SD卡 73 | */ 74 | public static Boolean copyAts(final Context mContext){ 75 | try { 76 | //检测引擎文件是否存在 77 | if (!new File(model1).exists() || !new File(model2).exists() || !new File(model3).exists()) { 78 | Log.i("Seetaface", "开始复制引擎到SD卡..."); 79 | SeetaUtil.copyAssetsToDst(mContext, ROOT_ASSETS, ROOT_CACHE); 80 | Log.i("Seetaface", "已成功复制引擎到SD卡"); 81 | return true; 82 | }else { 83 | Log.i("Seetaface", "引擎文件已在SD卡"); 84 | return true; 85 | } 86 | }catch (Exception e){ 87 | Log.i("Seetaface", "复制引擎文件异常:"+e.getMessage()); 88 | } 89 | return false; 90 | } 91 | 92 | /** 93 | * 引擎销毁 94 | */ 95 | public void destroy(){ 96 | if (faceDetector2!=null) { 97 | faceDetector2.dispose(); 98 | faceDetector2 = null; 99 | } 100 | if (pointDetector2!=null) { 101 | pointDetector2.dispose(); 102 | pointDetector2 = null; 103 | } 104 | if (faceRecognizer2!=null) { 105 | faceRecognizer2.dispose(); 106 | faceRecognizer2 = null; 107 | } 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /liseetaface2/src/main/java/com/seeta/sdk/util/SeetaUtil.java: -------------------------------------------------------------------------------- 1 | package com.seeta.sdk.util; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.os.Environment; 6 | 7 | import com.seeta.sdk.SeetaImageData; 8 | 9 | import java.io.File; 10 | import java.io.FileOutputStream; 11 | import java.io.InputStream; 12 | import java.nio.ByteBuffer; 13 | 14 | public class SeetaUtil { 15 | 16 | /** 17 | * 18 | * @param context 上下文对象 19 | * @param assPath assets目录中要拷贝的文件名 20 | * @param sdPath 放到SD卡中的文件名 21 | */ 22 | public static void copyAssetsToDst(Context context, String assPath, String sdPath) { 23 | try { 24 | String fileNames[] = context.getAssets().list(assPath); 25 | if (fileNames.length > 0) { 26 | File file = new File(/*Environment.getExternalStorageDirectory(), */sdPath); 27 | if (!file.exists()) file.mkdirs(); 28 | for (String fileName : fileNames) { 29 | if (!assPath.equals("")) { // assets 文件夹下的目录 30 | copyAssetsToDst(context, assPath + File.separator + fileName, sdPath + File.separator + fileName); 31 | } else { // assets 文件夹 32 | copyAssetsToDst(context, fileName, sdPath + File.separator + fileName); 33 | } 34 | } 35 | } else { 36 | File outFile = new File(/*Environment.getExternalStorageDirectory(), */sdPath); 37 | InputStream is = context.getAssets().open(assPath); 38 | FileOutputStream fos = new FileOutputStream(outFile); 39 | byte[] buffer = new byte[1024]; 40 | int byteCount; 41 | while ((byteCount = is.read(buffer)) != -1) { 42 | fos.write(buffer, 0, byteCount); 43 | } 44 | fos.flush(); 45 | is.close(); 46 | fos.close(); 47 | } 48 | } catch (Exception e) { 49 | e.printStackTrace(); 50 | }finally { 51 | context = null; 52 | } 53 | } 54 | 55 | /** 56 | * 转换生成SeetaImageData 57 | * @param bitmap 58 | * @return 59 | */ 60 | public static SeetaImageData ConvertToSeetaImageData(Bitmap bitmap) { 61 | Bitmap bmp_src = bitmap.copy(Bitmap.Config.ARGB_8888, true); // true is RGBA 62 | //SeetaImageData大小与原图像一致,但是通道数为3个通道即BGR 63 | SeetaImageData imageData = new SeetaImageData(bmp_src.getWidth(), bmp_src.getHeight(), 3); 64 | imageData.data = getPixelsBGR(bmp_src); 65 | return imageData; 66 | } 67 | 68 | /** 69 | * 提取图像中的BGR像素 70 | * @param image 71 | * @return 72 | */ 73 | public static byte[] getPixelsBGR(Bitmap image) { 74 | // calculate how many bytes our image consists of 75 | int bytes = image.getByteCount(); 76 | 77 | ByteBuffer buffer = ByteBuffer.allocate(bytes); // Create a new buffer 78 | image.copyPixelsToBuffer(buffer); // Move the byte data to the buffer 79 | 80 | byte[] temp = buffer.array(); // Get the underlying array containing the data. 81 | 82 | byte[] pixels = new byte[(temp.length/4) * 3]; // Allocate for BGR 83 | 84 | // Copy pixels into place 85 | for (int i = 0; i < temp.length/4; i++) { 86 | 87 | pixels[i * 3] = temp[i * 4 + 2]; //B 88 | pixels[i * 3 + 1] = temp[i * 4 + 1]; //G 89 | pixels[i * 3 + 2] = temp[i * 4 ]; //R 90 | 91 | } 92 | 93 | return pixels; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /liseetaface2/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | LiSeetaface2 3 | 4 | -------------------------------------------------------------------------------- /liseetaface2/src/test/java/com/seeta/sdk/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.seeta.sdk; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':liseetaface2' 2 | rootProject.name='SeetaFace2Demo' 3 | --------------------------------------------------------------------------------