├── .gitignore ├── .idea ├── encodings.xml ├── gradle.xml ├── misc.xml ├── runConfigurations.xml └── vcs.xml ├── app ├── .gitignore ├── build.gradle ├── libs │ └── armeabi-v7a │ │ ├── libFaceDetectorJni.so │ │ ├── libFaceRecognizerJni.so │ │ ├── libPointDetectorJni.so │ │ └── libholiday.so ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── itfitness │ │ └── seetaface2 │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ └── SeetaFaceDetector2.0.ats │ ├── java │ │ └── com │ │ │ └── itfitness │ │ │ └── seetaface2 │ │ │ ├── FaceDetectorActivity.java │ │ │ ├── FaceRecognizerActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── PointDetectorActivity.java │ │ │ ├── engine │ │ │ └── FaceEngine.java │ │ │ ├── facefind │ │ │ └── FaceFindActivity.java │ │ │ ├── facelogin │ │ │ ├── FaceInitActivity.java │ │ │ ├── FaceLoginActivity.java │ │ │ └── LoginActivity.java │ │ │ ├── utils │ │ │ ├── ConvertUtil.java │ │ │ └── FileUtil.java │ │ │ └── widget │ │ │ ├── FaceCameraView.java │ │ │ └── FaceRectView.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── heying.jpg │ │ ├── ic_launcher_background.xml │ │ ├── seetaface.jpg │ │ ├── tang01.png │ │ ├── tang02.jpg │ │ ├── tang03.jpg │ │ ├── tang04.jpg │ │ ├── tang05.png │ │ ├── tang06.png │ │ ├── tang07.jpg │ │ ├── tang08.jpg │ │ ├── tang09.png │ │ └── tang10.jpg │ │ ├── layout │ │ ├── activity_facedetector.xml │ │ ├── activity_facefind.xml │ │ ├── activity_facelogin.xml │ │ ├── activity_facerecognizer.xml │ │ ├── activity_login.xml │ │ ├── activity_main.xml │ │ └── activity_pointdetector.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 │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── itfitness │ └── seetaface2 │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── seetalibrary ├── .gitignore ├── build.gradle ├── 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 │ └── 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 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | buildToolsVersion "29.0.1" 6 | defaultConfig { 7 | applicationId "com.itfitness.seetaface2" 8 | minSdkVersion 15 9 | targetSdkVersion 28 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | ndk { 14 | abiFilters 'armeabi-v7a' 15 | } 16 | } 17 | sourceSets { 18 | main { 19 | jniLibs.srcDirs = ['libs'] 20 | } 21 | } 22 | buildTypes { 23 | release { 24 | minifyEnabled false 25 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 26 | } 27 | } 28 | } 29 | 30 | dependencies { 31 | implementation fileTree(dir: 'libs', include: ['*.jar']) 32 | implementation 'com.android.support:appcompat-v7:28.0.0' 33 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 34 | testImplementation 'junit:junit:4.12' 35 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 36 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 37 | implementation project(path: ':seetalibrary') 38 | } 39 | -------------------------------------------------------------------------------- /app/libs/armeabi-v7a/libFaceDetectorJni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myml666/Seetaface2/f56847e73e8cc1e430e6d641dcf7191078c8f70c/app/libs/armeabi-v7a/libFaceDetectorJni.so -------------------------------------------------------------------------------- /app/libs/armeabi-v7a/libFaceRecognizerJni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myml666/Seetaface2/f56847e73e8cc1e430e6d641dcf7191078c8f70c/app/libs/armeabi-v7a/libFaceRecognizerJni.so -------------------------------------------------------------------------------- /app/libs/armeabi-v7a/libPointDetectorJni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myml666/Seetaface2/f56847e73e8cc1e430e6d641dcf7191078c8f70c/app/libs/armeabi-v7a/libPointDetectorJni.so -------------------------------------------------------------------------------- /app/libs/armeabi-v7a/libholiday.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myml666/Seetaface2/f56847e73e8cc1e430e6d641dcf7191078c8f70c/app/libs/armeabi-v7a/libholiday.so -------------------------------------------------------------------------------- /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/itfitness/seetaface2/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.itfitness.seetaface2; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.itfitness.seetaface2", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/assets/SeetaFaceDetector2.0.ats: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myml666/Seetaface2/f56847e73e8cc1e430e6d641dcf7191078c8f70c/app/src/main/assets/SeetaFaceDetector2.0.ats -------------------------------------------------------------------------------- /app/src/main/java/com/itfitness/seetaface2/FaceDetectorActivity.java: -------------------------------------------------------------------------------- 1 | package com.itfitness.seetaface2; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapFactory; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.graphics.Rect; 9 | import android.support.v7.app.AppCompatActivity; 10 | import android.os.Bundle; 11 | import android.view.View; 12 | import android.widget.Button; 13 | import android.widget.ImageView; 14 | import com.itfitness.seetaface2.engine.FaceEngine; 15 | import com.itfitness.seetaface2.utils.ConvertUtil; 16 | import com.seeta.sdk.SeetaImageData; 17 | import com.seeta.sdk.SeetaRect; 18 | 19 | public class FaceDetectorActivity extends AppCompatActivity { 20 | private Button mBt; 21 | private ImageView mImg; 22 | private SeetaRect[] faceRects; 23 | private Bitmap bitmap; 24 | private SeetaImageData seetaImageData; 25 | 26 | @Override 27 | protected void onCreate(Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | setContentView(R.layout.activity_facedetector); 30 | //将模型拷贝到SD卡中 31 | //FileUtil.CopyAssets(this,"SeetaFaceDetector2.0.ats",Environment.getExternalStorageDirectory()+ File.separator+"SeetaFaceDetector2.0.ats"); 32 | initView(); 33 | initFace(); 34 | mBt.setOnClickListener(new View.OnClickListener() { 35 | @Override 36 | public void onClick(View v) { 37 | //如果图像中检测出人脸了再进行绘制 38 | if(faceRects.length>0){ 39 | //这里必须进行copy否则修改不了 40 | Bitmap copy = bitmap.copy(Bitmap.Config.ARGB_8888, true); 41 | //利用Bitmap创建Canvas,为了在图像上绘制人脸区域 42 | Canvas canvas = new Canvas(copy); 43 | Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); 44 | paint.setStyle(Paint.Style.STROKE); 45 | paint.setStrokeWidth(3); 46 | //绘制出所有的检测出来的人脸的区域 47 | for(int i = 0 ; i < faceRects.length ; i++){ 48 | paint.setColor(Color.BLUE); 49 | SeetaRect faceRect = faceRects[i]; 50 | Rect rect = new Rect(faceRect.x,faceRect.y,faceRect.x+faceRect.width,faceRect.y+faceRect.height); 51 | canvas.drawRect(rect,paint); 52 | } 53 | mImg.setImageBitmap(copy); 54 | } 55 | } 56 | }); 57 | } 58 | 59 | /** 60 | * 初始化人脸检测器 61 | */ 62 | private void initFace() { 63 | //初始化检测器(参数是模型在SD卡的位置) 64 | bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.heying); 65 | //利用SeetaFace2提供的转换方法获取SeetaRect(人脸识别结果) 66 | seetaImageData = ConvertUtil.ConvertToSeetaImageData(bitmap); 67 | if(FaceEngine.FACEDETECTOR!=null){ 68 | faceRects = FaceEngine.FACEDETECTOR.Detect(seetaImageData); 69 | } 70 | } 71 | 72 | private void initView() { 73 | mBt = findViewById(R.id.bt_face); 74 | mImg = findViewById(R.id.img); 75 | } 76 | 77 | @Override 78 | protected void onDestroy() { 79 | super.onDestroy(); 80 | //用了一个引擎后就不需要释放了 81 | // FaceEngine.FACEDETECTOR.dispose(); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/itfitness/seetaface2/FaceRecognizerActivity.java: -------------------------------------------------------------------------------- 1 | package com.itfitness.seetaface2; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapFactory; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.graphics.Rect; 9 | import android.os.Bundle; 10 | import android.os.Handler; 11 | import android.os.Message; 12 | import android.support.v7.app.AppCompatActivity; 13 | import android.util.Log; 14 | import android.view.View; 15 | import android.widget.Button; 16 | import android.widget.ImageView; 17 | import android.widget.Toast; 18 | 19 | import com.itfitness.seetaface2.engine.FaceEngine; 20 | import com.itfitness.seetaface2.utils.ConvertUtil; 21 | import com.seeta.sdk.SeetaImageData; 22 | import com.seeta.sdk.SeetaPointF; 23 | import com.seeta.sdk.SeetaRect; 24 | 25 | /** 26 | * 人脸匹配 27 | */ 28 | public class FaceRecognizerActivity extends AppCompatActivity { 29 | private Button mBt; 30 | private ImageView mImg; 31 | private int registerIndex; 32 | private boolean moduleFlag = false; 33 | private Handler handler = new Handler(){ 34 | @Override 35 | public void handleMessage(Message msg) { 36 | super.handleMessage(msg); 37 | mImg.setImageBitmap((Bitmap) msg.obj); 38 | } 39 | }; 40 | @Override 41 | protected void onCreate(Bundle savedInstanceState) { 42 | super.onCreate(savedInstanceState); 43 | setContentView(R.layout.activity_facerecognizer); 44 | //将模型拷贝到SD卡中 45 | initView(); 46 | initFace(); 47 | mBt.setOnClickListener(new View.OnClickListener() { 48 | @Override 49 | public void onClick(View v) { 50 | //如果人脸模型初始化成功了再操作 51 | if(moduleFlag){ 52 | Toast.makeText(FaceRecognizerActivity.this, "匹配中请稍等", Toast.LENGTH_SHORT).show(); 53 | new Thread(new Runnable() { 54 | @Override 55 | public void run() { 56 | //加载进行匹配的图像 57 | Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.tang08); 58 | //这里必须进行copy否则修改不了 59 | Bitmap copy = bitmap.copy(Bitmap.Config.ARGB_8888, true); 60 | //利用Bitmap创建Canvas,为了在图像上绘制人脸区域 61 | Canvas canvas = new Canvas(copy); 62 | Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); 63 | paint.setColor(Color.RED); 64 | paint.setStyle(Paint.Style.STROKE); 65 | paint.setStrokeWidth(3); 66 | SeetaImageData seetaImageData = ConvertUtil.ConvertToSeetaImageData(bitmap); 67 | //人脸检测 68 | SeetaRect[] detects = FaceEngine.FACEDETECTOR.Detect(seetaImageData); 69 | if(detects.length>0){ 70 | //将所有检测到的人脸与注册到数据库的人脸进行匹配 71 | for(int i = 0 ; i < detects.length ; i++){ 72 | SeetaRect faceRect = detects[i]; 73 | SeetaPointF[] seetaPoints = FaceEngine.POINTDETECTOR.Detect(seetaImageData, faceRect);//根据检测到的人脸进行特征点检测 74 | float[] similarity = new float[1];//用来存储人脸相似度值 75 | int targetIndex = FaceEngine.FACERECOGNIZER.Recognize(seetaImageData, seetaPoints, similarity);//匹配 76 | Log.e("人脸匹配",targetIndex+"======="+registerIndex+"====="+similarity[0]); 77 | //如果匹配值大于0.7说明是同一个人 78 | if(similarity[0]>0.7){ 79 | //将匹配出来的人脸区域绘制出来 80 | Rect rect = new Rect(faceRect.x,faceRect.y,faceRect.x+faceRect.width,faceRect.y+faceRect.height); 81 | canvas.drawRect(rect,paint); 82 | } 83 | } 84 | //通知主线程更新UI 85 | Message obtain = Message.obtain(); 86 | obtain.obj = copy; 87 | handler.sendMessage(obtain); 88 | } 89 | } 90 | }).start(); 91 | }else { 92 | Toast.makeText(FaceRecognizerActivity.this, "人脸模型尚未初始化成功请稍等", Toast.LENGTH_SHORT).show(); 93 | } 94 | } 95 | }); 96 | } 97 | 98 | /** 99 | * 初始化人脸检测器 100 | */ 101 | private void initFace() { 102 | new Thread(new Runnable() { 103 | @Override 104 | public void run() { 105 | Bitmap registBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.tang01); 106 | //利用SeetaFace2提供的转换方法获取SeetaRect(人脸识别结果) 107 | SeetaImageData RegistSeetaImageData = ConvertUtil.ConvertToSeetaImageData(registBitmap); 108 | SeetaRect[] faceRects = FaceEngine.FACEDETECTOR.Detect(RegistSeetaImageData); 109 | if(faceRects.length>0){ 110 | //获取人脸区域(这里只有一个所以取0) 111 | SeetaRect faceRect = faceRects[0]; 112 | SeetaPointF[] seetaPoints = FaceEngine.POINTDETECTOR.Detect(RegistSeetaImageData, faceRect);//根据检测到的人脸进行特征点检测 113 | registerIndex = FaceEngine.FACERECOGNIZER.Register(RegistSeetaImageData, seetaPoints);//将人脸注册到SeetaFace2数据库 114 | } 115 | runOnUiThread(new Runnable() { 116 | @Override 117 | public void run() { 118 | Toast.makeText(FaceRecognizerActivity.this, "人脸模型初始化成功", Toast.LENGTH_SHORT).show(); 119 | } 120 | }); 121 | //模型加载标记 122 | moduleFlag = true; 123 | } 124 | }).start(); 125 | } 126 | 127 | private void initView() { 128 | mBt = findViewById(R.id.bt_face); 129 | mImg = findViewById(R.id.img); 130 | } 131 | 132 | @Override 133 | protected void onDestroy() { 134 | super.onDestroy(); 135 | //释放 136 | //用了一个引擎后就不需要释放了 137 | // if(FaceEngine.FACEDETECTOR!=null){ 138 | // FaceEngine.FACEDETECTOR.dispose(); 139 | // } 140 | if(FaceEngine.FACERECOGNIZER!=null){ 141 | FaceEngine.FACERECOGNIZER.Clear();//清空注册的人脸 142 | // FaceEngine.FACERECOGNIZER.dispose(); 143 | } 144 | // if(FaceEngine.POINTDETECTOR!=null){ 145 | // FaceEngine.POINTDETECTOR.dispose(); 146 | // } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /app/src/main/java/com/itfitness/seetaface2/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.itfitness.seetaface2; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.view.View; 8 | import android.widget.Toast; 9 | 10 | import com.itfitness.seetaface2.engine.FaceEngine; 11 | import com.itfitness.seetaface2.facefind.FaceFindActivity; 12 | import com.itfitness.seetaface2.facelogin.FaceLoginActivity; 13 | 14 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { 15 | @Override 16 | protected void onCreate(@Nullable Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(R.layout.activity_main); 19 | //初始化引擎 20 | FaceEngine.init(); 21 | setClickListener(R.id.bt_one); 22 | setClickListener(R.id.bt_two); 23 | setClickListener(R.id.bt_three); 24 | setClickListener(R.id.bt_four); 25 | setClickListener(R.id.bt_five); 26 | } 27 | private void setClickListener(int id){ 28 | findViewById(id).setOnClickListener(this); 29 | } 30 | @Override 31 | public void onClick(View v) { 32 | if(!FaceEngine.INIT_SUCCESS){ 33 | Toast.makeText(this, "引擎尚未加载完毕请稍等", Toast.LENGTH_SHORT).show(); 34 | return; 35 | } 36 | switch (v.getId()){ 37 | case R.id.bt_one: 38 | gotoActivity(FaceDetectorActivity.class); 39 | break; 40 | case R.id.bt_two: 41 | gotoActivity(PointDetectorActivity.class); 42 | break; 43 | case R.id.bt_three: 44 | gotoActivity(FaceRecognizerActivity.class); 45 | break; 46 | case R.id.bt_four: 47 | gotoActivity(FaceLoginActivity.class); 48 | break; 49 | case R.id.bt_five: 50 | gotoActivity(FaceFindActivity.class); 51 | break; 52 | } 53 | } 54 | private void gotoActivity(Class clazz){ 55 | startActivity(new Intent(this,clazz)); 56 | } 57 | 58 | @Override 59 | protected void onDestroy() { 60 | super.onDestroy(); 61 | //释放 62 | //用了一个引擎后就不需要释放了 63 | if(FaceEngine.FACEDETECTOR!=null){ 64 | FaceEngine.FACEDETECTOR.dispose(); 65 | } 66 | if(FaceEngine.FACERECOGNIZER!=null){ 67 | FaceEngine.FACERECOGNIZER.Clear();//清空注册的人脸 68 | FaceEngine.FACERECOGNIZER.dispose(); 69 | } 70 | if(FaceEngine.POINTDETECTOR!=null){ 71 | FaceEngine.POINTDETECTOR.dispose(); 72 | } 73 | } 74 | } 75 | 76 | -------------------------------------------------------------------------------- /app/src/main/java/com/itfitness/seetaface2/PointDetectorActivity.java: -------------------------------------------------------------------------------- 1 | package com.itfitness.seetaface2; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapFactory; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.os.Bundle; 9 | import android.support.v7.app.AppCompatActivity; 10 | import android.view.View; 11 | import android.widget.Button; 12 | import android.widget.ImageView; 13 | 14 | import com.itfitness.seetaface2.engine.FaceEngine; 15 | import com.itfitness.seetaface2.utils.ConvertUtil; 16 | import com.seeta.sdk.SeetaImageData; 17 | import com.seeta.sdk.SeetaPointF; 18 | import com.seeta.sdk.SeetaRect; 19 | 20 | /** 21 | * 特征点检测 22 | */ 23 | public class PointDetectorActivity extends AppCompatActivity { 24 | private Button mBt; 25 | private ImageView mImg; 26 | private SeetaRect[] faceRects; 27 | private Bitmap bitmap; 28 | private SeetaImageData seetaImageData; 29 | 30 | @Override 31 | protected void onCreate(Bundle savedInstanceState) { 32 | super.onCreate(savedInstanceState); 33 | setContentView(R.layout.activity_pointdetector); 34 | //将模型拷贝到SD卡中 35 | //FileUtil.CopyAssets(this,"SeetaFaceDetector2.0.ats",Environment.getExternalStorageDirectory()+ File.separator+"SeetaFaceDetector2.0.ats"); 36 | initView(); 37 | initFace(); 38 | mBt.setOnClickListener(new View.OnClickListener() { 39 | @Override 40 | public void onClick(View v) { 41 | //如果图像中检测出人脸了再进行绘制 42 | if(faceRects.length>0){ 43 | //这里必须进行copy否则修改不了 44 | Bitmap copy = bitmap.copy(Bitmap.Config.ARGB_8888, true); 45 | //利用Bitmap创建Canvas,为了在图像上绘制人脸区域 46 | Canvas canvas = new Canvas(copy); 47 | Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); 48 | paint.setColor(Color.RED); 49 | paint.setStyle(Paint.Style.STROKE); 50 | paint.setStrokeWidth(3); 51 | //绘制出所有的检测出来的人脸的区域 52 | for(int i = 0 ; i < faceRects.length ; i++){ 53 | SeetaRect faceRect = faceRects[i]; 54 | SeetaPointF[] seetaPoints = FaceEngine.POINTDETECTOR.Detect(seetaImageData, faceRect);//根据检测到的人脸进行特征点检测 55 | if(seetaPoints.length>0){ 56 | for(SeetaPointF seetaPoint:seetaPoints){ 57 | //绘制特征点 58 | canvas.drawCircle((float) seetaPoint.x,(float) seetaPoint.y,5,paint); 59 | } 60 | } 61 | } 62 | mImg.setImageBitmap(copy); 63 | } 64 | } 65 | }); 66 | } 67 | 68 | /** 69 | * 初始化人脸检测器 70 | */ 71 | private void initFace() { 72 | //初始化检测器(参数是模型在SD卡的位置) 73 | bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.heying); 74 | //利用SeetaFace2提供的转换方法获取SeetaRect(人脸识别结果) 75 | seetaImageData = ConvertUtil.ConvertToSeetaImageData(bitmap); 76 | faceRects = FaceEngine.FACEDETECTOR.Detect(seetaImageData); 77 | } 78 | 79 | private void initView() { 80 | mBt = findViewById(R.id.bt_face); 81 | mImg = findViewById(R.id.img); 82 | } 83 | 84 | @Override 85 | protected void onDestroy() { 86 | super.onDestroy(); 87 | //用了一个引擎后就不需要释放了 88 | // if(FaceEngine.FACEDETECTOR!=null){ 89 | // FaceEngine.FACEDETECTOR.dispose(); 90 | // } 91 | // if(FaceEngine.POINTDETECTOR!=null){ 92 | // FaceEngine.POINTDETECTOR.dispose(); 93 | // } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /app/src/main/java/com/itfitness/seetaface2/engine/FaceEngine.java: -------------------------------------------------------------------------------- 1 | package com.itfitness.seetaface2.engine; 2 | 3 | import android.os.Environment; 4 | 5 | import com.seeta.sdk.FaceDetector2; 6 | import com.seeta.sdk.FaceRecognizer2; 7 | import com.seeta.sdk.PointDetector2; 8 | 9 | import java.io.File; 10 | 11 | public class FaceEngine { 12 | public static FaceDetector2 FACEDETECTOR; 13 | public static PointDetector2 POINTDETECTOR; 14 | public static FaceRecognizer2 FACERECOGNIZER; 15 | public static boolean INIT_SUCCESS = false;//是否加载成功 16 | /** 17 | * 初始化引擎 18 | */ 19 | public static void init(){ 20 | new Thread(new Runnable() { 21 | @Override 22 | public void run() { 23 | FACEDETECTOR = new FaceDetector2(Environment.getExternalStorageDirectory()+ File.separator+"seetaface"+File.separator+"SeetaFaceDetector2.0.ats"); 24 | POINTDETECTOR = new PointDetector2(Environment.getExternalStorageDirectory()+ File.separator+"seetaface"+File.separator+"SeetaPointDetector2.0.pts5.ats"); //特征点 25 | FACERECOGNIZER = new FaceRecognizer2(Environment.getExternalStorageDirectory()+ File.separator+"seetaface"+File.separator+"SeetaFaceRecognizer2.0.ats"); //人脸匹配 26 | INIT_SUCCESS = true; 27 | } 28 | }).start(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/itfitness/seetaface2/facefind/FaceFindActivity.java: -------------------------------------------------------------------------------- 1 | package com.itfitness.seetaface2.facefind; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.graphics.ImageFormat; 7 | import android.graphics.Matrix; 8 | import android.graphics.Rect; 9 | import android.graphics.YuvImage; 10 | import android.hardware.Camera; 11 | import android.os.Bundle; 12 | import android.os.Handler; 13 | import android.os.Message; 14 | import android.support.annotation.Nullable; 15 | import android.support.v7.app.AppCompatActivity; 16 | 17 | import com.itfitness.seetaface2.R; 18 | import com.itfitness.seetaface2.engine.FaceEngine; 19 | import com.itfitness.seetaface2.utils.ConvertUtil; 20 | import com.itfitness.seetaface2.widget.FaceCameraView; 21 | import com.itfitness.seetaface2.widget.FaceRectView; 22 | import com.seeta.sdk.SeetaImageData; 23 | import com.seeta.sdk.SeetaRect; 24 | 25 | import java.io.ByteArrayOutputStream; 26 | 27 | public class FaceFindActivity extends AppCompatActivity { 28 | private FaceCameraView faceCameraView; 29 | private FaceRectView faceRectView; 30 | private boolean isScaing = false; 31 | @SuppressLint("HandlerLeak") 32 | private Handler handler = new Handler() { 33 | @Override 34 | public void handleMessage(Message msg) { 35 | super.handleMessage(msg); 36 | faceRectView.setFaceDatas((SeetaRect[]) msg.obj); 37 | isScaing = false; 38 | } 39 | }; 40 | 41 | @Override 42 | protected void onCreate(@Nullable Bundle savedInstanceState) { 43 | super.onCreate(savedInstanceState); 44 | setContentView(R.layout.activity_facefind); 45 | initView(); 46 | initPreViewCallback(); 47 | } 48 | 49 | private void initPreViewCallback() { 50 | faceCameraView.setPreviewCallback(new FaceCameraView.PreviewCallback() { 51 | @Override 52 | public void onPreview(final byte[] data, final Camera camera) { 53 | if (FaceEngine.FACEDETECTOR != null && FaceEngine.FACERECOGNIZER != null && FaceEngine.POINTDETECTOR != null) { 54 | new Thread(new Runnable() { 55 | @Override 56 | public void run() { 57 | //识别中不处理其他帧数据 58 | if (!isScaing) { 59 | isScaing = true; 60 | try { 61 | //获取Camera预览尺寸 62 | Camera.Size size = camera.getParameters().getPreviewSize(); 63 | //将帧数据转为bitmap 64 | YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null); 65 | if (image != null) { 66 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); 67 | image.compressToJpeg(new Rect(0, 0, size.width, size.height), 80, stream); 68 | Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size()); 69 | //纠正图像的旋转角度问题 70 | Matrix m = new Matrix(); 71 | m.setRotate(-90, (float) bmp.getWidth() / 2, (float) bmp.getHeight() / 2); 72 | Bitmap bm = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), m, true); 73 | SeetaImageData loginSeetaImageData = ConvertUtil.ConvertToSeetaImageData(bm); 74 | SeetaRect[] faceRects = FaceEngine.FACEDETECTOR.Detect(loginSeetaImageData); 75 | if(faceRects.length>0){ 76 | Message obtain = Message.obtain(); 77 | obtain.obj = faceRects; 78 | handler.sendMessage(obtain); 79 | } 80 | } 81 | } catch (Exception ex) { 82 | isScaing = false; 83 | } 84 | } 85 | } 86 | } 87 | ).start(); 88 | } 89 | } 90 | }); 91 | } 92 | 93 | private void initView() { 94 | faceCameraView = findViewById(R.id.camera_findface); 95 | faceRectView = findViewById(R.id.facerect); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /app/src/main/java/com/itfitness/seetaface2/facelogin/FaceInitActivity.java: -------------------------------------------------------------------------------- 1 | package com.itfitness.seetaface2.facelogin; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapFactory; 5 | import android.graphics.ImageFormat; 6 | import android.graphics.Matrix; 7 | import android.graphics.Rect; 8 | import android.graphics.YuvImage; 9 | import android.hardware.Camera; 10 | import android.os.Bundle; 11 | import android.os.Handler; 12 | import android.os.Message; 13 | import android.support.v7.app.AppCompatActivity; 14 | import android.widget.Toast; 15 | 16 | import com.itfitness.seetaface2.R; 17 | import com.itfitness.seetaface2.widget.FaceCameraView; 18 | import com.itfitness.seetaface2.engine.FaceEngine; 19 | import com.itfitness.seetaface2.utils.ConvertUtil; 20 | import com.seeta.sdk.SeetaImageData; 21 | import com.seeta.sdk.SeetaPointF; 22 | import com.seeta.sdk.SeetaRect; 23 | 24 | import java.io.ByteArrayOutputStream; 25 | 26 | public class FaceInitActivity extends AppCompatActivity{ 27 | private FaceCameraView faceInitCameraView; 28 | private boolean isScanning = false; 29 | Handler handler = new Handler() { 30 | @Override 31 | public void handleMessage(Message msg) { 32 | super.handleMessage(msg); 33 | Toast.makeText(FaceInitActivity.this, "信息录入成功", Toast.LENGTH_SHORT).show(); 34 | finish(); 35 | } 36 | }; 37 | @Override 38 | protected void onCreate(Bundle savedInstanceState) { 39 | super.onCreate(savedInstanceState); 40 | setContentView(R.layout.activity_login); 41 | initView(); 42 | } 43 | private void initView(){ 44 | faceInitCameraView = (FaceCameraView) findViewById(R.id.camera2); 45 | faceInitCameraView.setPreviewCallback(new FaceCameraView.PreviewCallback() { 46 | @Override 47 | public void onPreview(final byte[] data, final Camera camera) { 48 | if(FaceEngine.FACEDETECTOR!=null&&FaceEngine.FACERECOGNIZER!=null&&FaceEngine.POINTDETECTOR!=null){ 49 | new Thread(new Runnable() { 50 | @Override 51 | public void run() { 52 | //识别中不处理其他帧数据 53 | if (!isScanning) { 54 | isScanning = true; 55 | try { 56 | //获取Camera预览尺寸 57 | Camera.Size size = camera.getParameters().getPreviewSize(); 58 | //将帧数据转为bitmap 59 | YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null); 60 | if (image != null) { 61 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); 62 | image.compressToJpeg(new Rect(0, 0, size.width, size.height), 80, stream); 63 | Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size()); 64 | //纠正图像的旋转角度问题 65 | Matrix m = new Matrix(); 66 | m.setRotate(-90, (float) bmp.getWidth() / 2, (float) bmp.getHeight() / 2); 67 | Bitmap bm = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), m, true); 68 | SeetaImageData RegistSeetaImageData = ConvertUtil.ConvertToSeetaImageData(bm); 69 | SeetaRect[] faceRects = FaceEngine.FACEDETECTOR.Detect(RegistSeetaImageData); 70 | if(faceRects.length>0){ 71 | //获取人脸区域(这里只有一个所以取0) 72 | SeetaRect faceRect = faceRects[0]; 73 | SeetaPointF[] seetaPoints = FaceEngine.POINTDETECTOR.Detect(RegistSeetaImageData, faceRect);//根据检测到的人脸进行特征点检测 74 | FaceEngine.FACERECOGNIZER.Register(RegistSeetaImageData, seetaPoints);//将人脸注册到SeetaFace2数据库 75 | handler.sendEmptyMessage(0); 76 | }else { 77 | //如果检测不到人脸给予如下提示 78 | runOnUiThread(new Runnable() { 79 | @Override 80 | public void run() { 81 | Toast.makeText(FaceInitActivity.this, "请保持手机不要晃动", Toast.LENGTH_SHORT).show(); 82 | } 83 | }); 84 | isScanning = false; 85 | } 86 | } 87 | } catch (Exception ex) { 88 | isScanning = false; 89 | } 90 | } 91 | } 92 | } 93 | ).start(); 94 | } 95 | } 96 | }); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /app/src/main/java/com/itfitness/seetaface2/facelogin/FaceLoginActivity.java: -------------------------------------------------------------------------------- 1 | package com.itfitness.seetaface2.facelogin; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.view.View; 8 | import com.itfitness.seetaface2.R; 9 | 10 | import static com.itfitness.seetaface2.engine.FaceEngine.FACERECOGNIZER; 11 | 12 | public class FaceLoginActivity extends AppCompatActivity implements View.OnClickListener { 13 | @Override 14 | protected void onCreate(@Nullable Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_facelogin); 17 | setClickListener(R.id.bt_initfacedata); 18 | setClickListener(R.id.bt_facelogin); 19 | } 20 | 21 | private void setClickListener(int id){ 22 | findViewById(id).setOnClickListener(this); 23 | } 24 | @Override 25 | public void onClick(View v) { 26 | switch (v.getId()){ 27 | case R.id.bt_initfacedata: 28 | //录入人脸信息 29 | gotoActivity(FaceInitActivity.class); 30 | break; 31 | case R.id.bt_facelogin: 32 | //人脸登录 33 | gotoActivity(LoginActivity.class); 34 | break; 35 | } 36 | } 37 | private void gotoActivity(Class clazz){ 38 | startActivity(new Intent(this,clazz)); 39 | } 40 | 41 | @Override 42 | protected void onDestroy() { 43 | super.onDestroy(); 44 | //清空人脸数据 45 | if(FACERECOGNIZER!=null){ 46 | FACERECOGNIZER.Clear(); 47 | // FACERECOGNIZER.dispose(); 48 | } 49 | //用了一个引擎后就不需要释放了 50 | // if(POINTDETECTOR!=null){ 51 | // POINTDETECTOR.dispose(); 52 | // } 53 | // if(FACEDETECTOR!=null){ 54 | // FACEDETECTOR.dispose(); 55 | // } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/itfitness/seetaface2/facelogin/LoginActivity.java: -------------------------------------------------------------------------------- 1 | package com.itfitness.seetaface2.facelogin; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapFactory; 5 | import android.graphics.ImageFormat; 6 | import android.graphics.Matrix; 7 | import android.graphics.Rect; 8 | import android.graphics.YuvImage; 9 | import android.hardware.Camera; 10 | import android.os.Bundle; 11 | import android.os.Handler; 12 | import android.os.Message; 13 | import android.support.v7.app.AppCompatActivity; 14 | import android.widget.Toast; 15 | import com.itfitness.seetaface2.R; 16 | import com.itfitness.seetaface2.widget.FaceCameraView; 17 | import com.itfitness.seetaface2.engine.FaceEngine; 18 | import com.itfitness.seetaface2.utils.ConvertUtil; 19 | import com.seeta.sdk.SeetaImageData; 20 | import com.seeta.sdk.SeetaPointF; 21 | import com.seeta.sdk.SeetaRect; 22 | import java.io.ByteArrayOutputStream; 23 | public class LoginActivity extends AppCompatActivity{ 24 | private FaceCameraView faceCameraView; 25 | private boolean isScanning = false; 26 | private int failedCount = 0;//失败次数 27 | Handler handler = new Handler() { 28 | @Override 29 | public void handleMessage(Message msg) { 30 | super.handleMessage(msg); 31 | switch (msg.what){ 32 | case 0: 33 | failedCount++; 34 | if(failedCount>=5){ 35 | Toast.makeText(LoginActivity.this, "人脸不匹配,登录失败", Toast.LENGTH_SHORT).show(); 36 | finish(); 37 | } 38 | isScanning = false; 39 | break; 40 | case 1: 41 | Toast.makeText(LoginActivity.this, "登录成功", Toast.LENGTH_SHORT).show(); 42 | finish(); 43 | break; 44 | } 45 | } 46 | }; 47 | @Override 48 | protected void onCreate(Bundle savedInstanceState) { 49 | super.onCreate(savedInstanceState); 50 | setContentView(R.layout.activity_login); 51 | initView(); 52 | } 53 | private void initView(){ 54 | faceCameraView = (FaceCameraView) findViewById(R.id.camera2); 55 | faceCameraView.setPreviewCallback(new FaceCameraView.PreviewCallback() { 56 | @Override 57 | public void onPreview(final byte[] data, final Camera camera) { 58 | if(FaceEngine.FACEDETECTOR!=null&&FaceEngine.FACERECOGNIZER!=null&&FaceEngine.POINTDETECTOR!=null){ 59 | new Thread(new Runnable() { 60 | @Override 61 | public void run() { 62 | //识别中不处理其他帧数据 63 | if (!isScanning) { 64 | isScanning = true; 65 | try { 66 | //获取Camera预览尺寸 67 | Camera.Size size = camera.getParameters().getPreviewSize(); 68 | //将帧数据转为bitmap 69 | YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null); 70 | if (image != null) { 71 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); 72 | image.compressToJpeg(new Rect(0, 0, size.width, size.height), 80, stream); 73 | Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size()); 74 | //纠正图像的旋转角度问题 75 | Matrix m = new Matrix(); 76 | m.setRotate(-90, (float) bmp.getWidth() / 2, (float) bmp.getHeight() / 2); 77 | Bitmap bm = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), m, true); 78 | SeetaImageData loginSeetaImageData = ConvertUtil.ConvertToSeetaImageData(bm); 79 | SeetaRect[] faceRects = FaceEngine.FACEDETECTOR.Detect(loginSeetaImageData); 80 | if(faceRects.length>0){ 81 | //获取人脸区域(这里只有一个所以取0) 82 | SeetaRect faceRect = faceRects[0]; 83 | SeetaPointF[] seetaPoints = FaceEngine.POINTDETECTOR.Detect(loginSeetaImageData, faceRect);//根据检测到的人脸进行特征点检测 84 | float[] similarity = new float[1];//用来存储人脸相似度值 85 | FaceEngine.FACERECOGNIZER.Recognize(loginSeetaImageData, seetaPoints, similarity);//匹配 86 | if(similarity[0]>0.7){ 87 | handler.sendEmptyMessage(1); 88 | }else { 89 | handler.sendEmptyMessage(0); 90 | } 91 | }else { 92 | runOnUiThread(new Runnable() { 93 | @Override 94 | public void run() { 95 | Toast.makeText(LoginActivity.this, "请保持手机不要晃动", Toast.LENGTH_SHORT).show(); 96 | } 97 | }); 98 | isScanning = false; 99 | } 100 | } 101 | } catch (Exception ex) { 102 | isScanning = false; 103 | } 104 | } 105 | } 106 | } 107 | ).start(); 108 | } 109 | } 110 | }); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /app/src/main/java/com/itfitness/seetaface2/utils/ConvertUtil.java: -------------------------------------------------------------------------------- 1 | package com.itfitness.seetaface2.utils; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapFactory; 5 | 6 | import com.itfitness.seetaface2.R; 7 | import com.seeta.sdk.SeetaImageData; 8 | 9 | import java.nio.ByteBuffer; 10 | 11 | public class ConvertUtil { 12 | /** 13 | * 转换生成SeetaImageData 14 | * @param bitmap 15 | * @return 16 | */ 17 | public static SeetaImageData ConvertToSeetaImageData(Bitmap bitmap) { 18 | Bitmap bmp_src = bitmap.copy(Bitmap.Config.ARGB_8888, true); // true is RGBA 19 | //SeetaImageData大小与原图像一致,但是通道数为3个通道即BGR 20 | SeetaImageData imageData = new SeetaImageData(bmp_src.getWidth(), bmp_src.getHeight(), 3); 21 | imageData.data = getPixelsBGR(bmp_src); 22 | return imageData; 23 | } 24 | 25 | /** 26 | * 提取图像中的BGR像素 27 | * @param image 28 | * @return 29 | */ 30 | public static byte[] getPixelsBGR(Bitmap image) { 31 | // calculate how many bytes our image consists of 32 | int bytes = image.getByteCount(); 33 | 34 | ByteBuffer buffer = ByteBuffer.allocate(bytes); // Create a new buffer 35 | image.copyPixelsToBuffer(buffer); // Move the byte data to the buffer 36 | 37 | byte[] temp = buffer.array(); // Get the underlying array containing the data. 38 | 39 | byte[] pixels = new byte[(temp.length/4) * 3]; // Allocate for BGR 40 | 41 | // Copy pixels into place 42 | for (int i = 0; i < temp.length/4; i++) { 43 | 44 | pixels[i * 3] = temp[i * 4 + 2]; //B 45 | pixels[i * 3 + 1] = temp[i * 4 + 1]; //G 46 | pixels[i * 3 + 2] = temp[i * 4 ]; //R 47 | 48 | } 49 | 50 | return pixels; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/itfitness/seetaface2/utils/FileUtil.java: -------------------------------------------------------------------------------- 1 | package com.itfitness.seetaface2.utils; 2 | 3 | import android.content.Context; 4 | 5 | import java.io.File; 6 | import java.io.FileOutputStream; 7 | import java.io.InputStream; 8 | 9 | public class FileUtil { 10 | /** 11 | * 12 | * @param context 上下文对象 13 | * @param oldPath assets目录中要拷贝的文件名 14 | * @param newPath 放到SD卡中的文件名 15 | */ 16 | public static void CopyAssets(Context context, String oldPath, String newPath) { 17 | try { 18 | String fileNames[] = context.getAssets().list(oldPath);// 获取assets目录下的所有文件及目录名 19 | if (fileNames.length > 0) {// 如果是目录 20 | File file = new File(newPath); 21 | file.mkdirs();// 如果文件夹不存在,则递归 22 | for (String fileName : fileNames) { 23 | CopyAssets(context, oldPath + "/" + fileName, newPath + "/" + fileName); 24 | } 25 | } else {// 如果是文件 26 | InputStream is = context.getAssets().open(oldPath); 27 | FileOutputStream fos = new FileOutputStream(new File(newPath)); 28 | byte[] buffer = new byte[1024]; 29 | int byteCount = 0; 30 | while ((byteCount = is.read(buffer)) != -1) {// 循环从输入流读取 31 | // buffer字节 32 | fos.write(buffer, 0, byteCount);// 将读取的输入流写入到输出流 33 | } 34 | fos.flush();// 刷新缓冲区 35 | is.close(); 36 | fos.close(); 37 | } 38 | } catch (Exception e) { 39 | e.printStackTrace(); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/itfitness/seetaface2/widget/FaceCameraView.java: -------------------------------------------------------------------------------- 1 | package com.itfitness.seetaface2.widget; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageManager; 5 | import android.graphics.ImageFormat; 6 | import android.hardware.Camera; 7 | import android.util.AttributeSet; 8 | import android.util.DisplayMetrics; 9 | import android.view.SurfaceHolder; 10 | import android.view.SurfaceView; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * 自定义相机 16 | */ 17 | 18 | public class FaceCameraView extends SurfaceView implements SurfaceHolder.Callback, Camera.PreviewCallback { 19 | private Camera mCamera;//相机 20 | private boolean isSupportAutoFocus;//是否支持自动对焦 21 | private int screenHeight;//屏幕的高度 22 | private int screenWidth;//屏幕的宽度 23 | private boolean isPreviewing;//是否在预览 24 | private PreviewCallback previewCallback;//相机预览的回调 25 | public FaceCameraView(Context context) { 26 | super(context); 27 | init(); 28 | } 29 | 30 | public FaceCameraView(Context context, AttributeSet attrs) { 31 | super(context, attrs); 32 | init(); 33 | } 34 | 35 | public FaceCameraView(Context context, AttributeSet attrs, int defStyleAttr) { 36 | super(context, attrs, defStyleAttr); 37 | init(); 38 | } 39 | 40 | private void init() { 41 | DisplayMetrics dm = getContext().getResources().getDisplayMetrics(); 42 | screenWidth = dm.heightPixels; 43 | screenHeight = dm.widthPixels; 44 | isSupportAutoFocus = getContext().getPackageManager().hasSystemFeature( 45 | PackageManager.FEATURE_CAMERA_AUTOFOCUS); 46 | getHolder().addCallback(this); 47 | getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 48 | } 49 | 50 | public void setPreviewCallback(PreviewCallback previewCallback) { 51 | this.previewCallback = previewCallback; 52 | } 53 | 54 | /** 55 | * Camera帧数据回调用 56 | */ 57 | @Override 58 | public void onPreviewFrame(final byte[] data, final Camera camera) { 59 | camera.addCallbackBuffer(data); 60 | if(previewCallback!=null){ 61 | previewCallback.onPreview(data,camera); 62 | } 63 | } 64 | 65 | /** 66 | * 摄像头自动聚焦 67 | */ 68 | Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() { 69 | public void onAutoFocus(boolean success, Camera camera) { 70 | postDelayed(doAutoFocus, 500); 71 | } 72 | }; 73 | private Runnable doAutoFocus = new Runnable() { 74 | public void run() { 75 | if (mCamera != null) { 76 | try { 77 | mCamera.autoFocus(autoFocusCB); 78 | } catch (Exception e) { 79 | } 80 | } 81 | } 82 | }; 83 | 84 | /** 85 | * 打开指定摄像头 86 | */ 87 | public void openCamera() { 88 | Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); 89 | for (int cameraId = 0; cameraId < Camera.getNumberOfCameras(); cameraId++) { 90 | Camera.getCameraInfo(cameraId, cameraInfo); 91 | //打开前置摄像头 92 | if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { 93 | try { 94 | mCamera = Camera.open(cameraId); 95 | } catch (Exception e) { 96 | if (mCamera != null) { 97 | mCamera.release(); 98 | mCamera = null; 99 | } 100 | } 101 | break; 102 | } 103 | } 104 | } 105 | 106 | @Override 107 | public void surfaceCreated(SurfaceHolder holder) { 108 | try { 109 | releaseCamera(); 110 | openCamera(); 111 | } catch (Exception e) { 112 | mCamera = null; 113 | } 114 | } 115 | 116 | /** 117 | * 加载相机配置 118 | */ 119 | private void initCamera() { 120 | try { 121 | mCamera.setPreviewDisplay(getHolder());//当前控件显示相机数据 122 | mCamera.setDisplayOrientation(90);//调整预览角度 123 | setCameraParameters(); 124 | startPreview();//打开相机 125 | } catch (Exception e) { 126 | releaseCamera(); 127 | } 128 | } 129 | 130 | /** 131 | * 配置相机参数 132 | */ 133 | private void setCameraParameters() { 134 | Camera.Parameters parameters = mCamera.getParameters(); 135 | List sizes = parameters.getSupportedPreviewSizes(); 136 | //确定前面定义的预览宽高是camera支持的,不支持取就更大的 137 | for (int i = 0; i < sizes.size(); i++) { 138 | if ((sizes.get(i).width >= screenWidth && sizes.get(i).height >= screenHeight) || i == sizes.size() - 1) { 139 | screenWidth = sizes.get(i).width; 140 | screenHeight = sizes.get(i).height; 141 | break; 142 | } 143 | } 144 | //设置最终确定的预览大小 145 | parameters.setPreviewSize(screenWidth, screenHeight); 146 | mCamera.setParameters(parameters); 147 | } 148 | 149 | /** 150 | * 释放相机 151 | */ 152 | private void releaseCamera() { 153 | if (mCamera != null) { 154 | stopPreview(); 155 | mCamera.setPreviewCallback(null); 156 | mCamera.release(); 157 | mCamera = null; 158 | } 159 | } 160 | 161 | /** 162 | * 停止预览 163 | */ 164 | private void stopPreview() { 165 | if (mCamera != null && isPreviewing) { 166 | mCamera.stopPreview(); 167 | isPreviewing = false; 168 | } 169 | } 170 | 171 | /** 172 | * 开始预览 173 | */ 174 | public void startPreview() { 175 | if (mCamera != null) { 176 | mCamera.addCallbackBuffer(new byte[((screenWidth * screenHeight) * ImageFormat.getBitsPerPixel(ImageFormat.NV21)) / 8]); 177 | mCamera.setPreviewCallbackWithBuffer(this); 178 | mCamera.startPreview(); 179 | if (isSupportAutoFocus) { 180 | mCamera.autoFocus(autoFocusCB); 181 | } 182 | isPreviewing = true; 183 | } 184 | } 185 | 186 | @Override 187 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 188 | stopPreview(); 189 | initCamera(); 190 | } 191 | 192 | @Override 193 | public void surfaceDestroyed(SurfaceHolder holder) { 194 | releaseCamera(); 195 | } 196 | 197 | public interface PreviewCallback { 198 | /** 199 | * 相机预览的回调接口 200 | * @param data 201 | * @param camera 202 | */ 203 | void onPreview(final byte[] data, final Camera camera); 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /app/src/main/java/com/itfitness/seetaface2/widget/FaceRectView.java: -------------------------------------------------------------------------------- 1 | package com.itfitness.seetaface2.widget; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.graphics.RectF; 9 | import android.support.annotation.Nullable; 10 | import android.util.AttributeSet; 11 | import android.util.Log; 12 | import android.view.View; 13 | 14 | import com.seeta.sdk.SeetaRect; 15 | 16 | /** 17 | * 用于绘制识别出来的人脸区域 18 | */ 19 | public class FaceRectView extends View { 20 | private Paint mPaint; 21 | private SeetaRect[] faceRects; 22 | 23 | public FaceRectView(Context context) { 24 | this(context, null); 25 | } 26 | 27 | public FaceRectView(Context context, @Nullable AttributeSet attrs) { 28 | this(context, attrs, 0); 29 | } 30 | 31 | public FaceRectView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 32 | super(context, attrs, defStyleAttr); 33 | init(); 34 | } 35 | 36 | private void init() { 37 | //初始化画笔 38 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 39 | mPaint.setColor(Color.GREEN);//绿色画笔 40 | mPaint.setStyle(Paint.Style.STROKE); 41 | mPaint.setStrokeWidth(5); 42 | } 43 | 44 | @Override 45 | protected void onDraw(Canvas canvas) { 46 | super.onDraw(canvas); 47 | Log.e("绘制","非空"); 48 | if (faceRects!=null && faceRects.length > 0) { 49 | Log.e("绘制","非空"); 50 | for (SeetaRect faceRect : faceRects) { 51 | Log.e("绘制",faceRect.x+"===="+faceRect.y+"====="+faceRect.width+"====="+faceRect.height); 52 | canvas.drawRect(new RectF(faceRect.x, faceRect.y, faceRect.x + faceRect.width, faceRect.y + faceRect.height), mPaint); 53 | } 54 | }else { 55 | Log.e("绘制","空"); 56 | } 57 | } 58 | 59 | /** 60 | * 设置人脸数据 61 | * 62 | * @param faceRects 63 | */ 64 | public void setFaceDatas(SeetaRect[] faceRects) { 65 | Log.e("设置",faceRects[0].x+"===="+faceRects[0].y+"====="+faceRects[0].width+"====="+faceRects[0].height); 66 | this.faceRects = faceRects; 67 | invalidate(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /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/heying.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myml666/Seetaface2/f56847e73e8cc1e430e6d641dcf7191078c8f70c/app/src/main/res/drawable/heying.jpg -------------------------------------------------------------------------------- /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/drawable/seetaface.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myml666/Seetaface2/f56847e73e8cc1e430e6d641dcf7191078c8f70c/app/src/main/res/drawable/seetaface.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/tang01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myml666/Seetaface2/f56847e73e8cc1e430e6d641dcf7191078c8f70c/app/src/main/res/drawable/tang01.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/tang02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myml666/Seetaface2/f56847e73e8cc1e430e6d641dcf7191078c8f70c/app/src/main/res/drawable/tang02.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/tang03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myml666/Seetaface2/f56847e73e8cc1e430e6d641dcf7191078c8f70c/app/src/main/res/drawable/tang03.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/tang04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myml666/Seetaface2/f56847e73e8cc1e430e6d641dcf7191078c8f70c/app/src/main/res/drawable/tang04.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/tang05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myml666/Seetaface2/f56847e73e8cc1e430e6d641dcf7191078c8f70c/app/src/main/res/drawable/tang05.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/tang06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myml666/Seetaface2/f56847e73e8cc1e430e6d641dcf7191078c8f70c/app/src/main/res/drawable/tang06.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/tang07.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myml666/Seetaface2/f56847e73e8cc1e430e6d641dcf7191078c8f70c/app/src/main/res/drawable/tang07.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/tang08.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myml666/Seetaface2/f56847e73e8cc1e430e6d641dcf7191078c8f70c/app/src/main/res/drawable/tang08.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/tang09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myml666/Seetaface2/f56847e73e8cc1e430e6d641dcf7191078c8f70c/app/src/main/res/drawable/tang09.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/tang10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myml666/Seetaface2/f56847e73e8cc1e430e6d641dcf7191078c8f70c/app/src/main/res/drawable/tang10.jpg -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_facedetector.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 |