提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 一、人脸检测是什么?
- 二、使用步骤
- 1.引入库
- 2.分包操作
- 3.添加自定义MyApplication
- 4.NetworkRequiredInfo
- 5.AppContext
- 5.ApiService接口类
- 人脸识别activity
前言
最近在写一个人脸识别的小练习,现在记录一下
一、人脸检测是什么?
从手机照片获取一张人脸照片,进行检测,调用百度ai人脸检测接口。
二、使用步骤
1.引入库
代码如下(示例):
implementation 'com.orhanobut:hawk:2.0.1'//数据存储
//图片加载框架
implementation 'com.github.bumptech.glide:glide:4.11.0'
implementation 'com.github.bumptech.glide:compiler:4.11.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
implementation 'io.reactivex.rxjava2:rxjava:2.2.12'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1")
implementation("androidx.fragment:fragment-ktx:1.4.1")
2.分包操作
项目包名如图所示:
3.添加自定义MyApplication
在application中添加一个类名为MyApplication的类
public class MyApplication extends Application {
static Context context;
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
Hawk.init(this).build();
//初始化
NetworkApi.init(new NetworkRequiredInfo(this));
}
public static synchronized MyApplication context() {
return (MyApplication) context;
}
/**
*Show Toast 简单封装
*/
public static void showToastLong(String msg) {
showToast(context, msg, Toast.LENGTH_LONG);
}
public static void showToastShort(String msg) {
showToast(context, msg, Toast.LENGTH_SHORT);
}
public static void showToastShort(int strRes) {
showToast(context, context.getString(strRes), Toast.LENGTH_SHORT);
}
public static void showToast(String msg) {
showToast(context, msg, Toast.LENGTH_SHORT);
}
public static void showToast(int strRes) {
showToast(context, context.getString(strRes), Toast.LENGTH_SHORT);
}
public static void showToastLong(int strRes) {
showToast(context, context.getString(strRes), Toast.LENGTH_LONG);
}
public static void showToast(Context context, String msg, int duration) {
Toast.makeText(context, msg, duration).show();
}
}
4.NetworkRequiredInfo
在application中添加一个类名为NetworkRequiredInfo 的类
public class NetworkRequiredInfo implements INetworkRequiredInfo {
private Application application;
public NetworkRequiredInfo(Application application){
this.application = application;
}
/**
* 版本名
*/
@Override
public String getAppVersionName() {
return "1";
}
/**
* 版本号
*/
@Override
public String getAppVersionCode() {
return "1.0";
}
/**
* 是否为debug
*/
@Override
public boolean isDebug() {
return BuildConfig.DEBUG;
}
/**
* 应用全局上下文
*/
@Override
public Application getApplicationContext() {
return application;
}
}
5.AppContext
在application中添加一个类名为AppContext的类
public class AppContext extends MyApplication {
private static AppContext instance;
@Override
public void onCreate() {
super.onCreate();
instance = this;
}
/**
* 获得当前app运行的AppContext
*/
public static AppContext getInstance() {
return instance;
}
/**
* ResponseBody 处理成 Json
*/
public static String doJson(ResponseBody responseBody) {
long contentLength = responseBody.contentLength();
BufferedSource source = responseBody.source();
try {
source.request(Long.MAX_VALUE); // Buffer the entire body.
} catch (IOException e) {
e.printStackTrace();
}
Buffer buffer = source.buffer();
Charset charset = UTF8;
MediaType contentType = responseBody.contentType();
if (contentType != null) {
try {
charset = contentType.charset(UTF8);
} catch (UnsupportedCharsetException e) {
e.printStackTrace();
}
}
String result = "";
// 拦截器,
if (contentLength != 0) {
result = buffer.clone().readString(charset);
// Log.e("MainActivity", " doJson====>:" + result);
}
return result;
}
private static final Charset UTF8 = Charset.forName("UTF-8");
/***
* 将指定路径的图片转uri
* @param context
* @param path ,指定图片(或文件)的路径
* @return
*/
@SuppressLint("Range") public static Uri getMediaUriFromPath(Context context, String path) {
Uri mediaUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
Cursor cursor = context.getContentResolver().query(mediaUri,
null,
MediaStore.Images.Media.DISPLAY_NAME + "= ?",
new String[] { path.substring(path.lastIndexOf("/") + 1) },
null);
Uri uri = null;
if (cursor.moveToFirst()) {
uri = ContentUris.withAppendedId(mediaUri,
cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media._ID)));
}
cursor.close();
return uri;
}
/**
* 将相册uri转换成url
*/
public static String getRealPathFromURI(Context context, Uri contentURI) {
String result;
Cursor cursor = context.getContentResolver().query(contentURI,
new String[] { MediaStore.Images.ImageColumns.DATA },//
null, null, null);
if (cursor == null) { result = contentURI.getPath(); } else {
cursor.moveToFirst();
int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
result = cursor.getString(index);
cursor.close();
}
return result;
}
/**
* 将拍照的图片保存到系统相册
*/
public static String saveImageToGallery(Context context, Bitmap bmp) {
String fileName = "zhengfutanfang" + ".jpg";
//检查有没有存储权限
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
AppContext.showToast("请至权限中心打开应用权限");
return "saveError";
} else {
// 新建目录appDir,并把图片存到其下
File appDir = new File(context.getExternalFilesDir(null).getPath() + "BarcodeBitmap");
if (!appDir.exists()) {
appDir.mkdir();
}
File file = new File(appDir, fileName);
try {
FileOutputStream fos = new FileOutputStream(file);
bmp.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// 把file里面的图片插入到系统相册中
try {
MediaStore.Images.Media.insertImage(context.getContentResolver(),
file.getAbsolutePath(), fileName, null);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// 通知相册更新
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)));
return context.getExternalFilesDir(null).getPath() + "BarcodeBitmap/" + fileName;
}
}
}
5.ApiService接口类
在service包中添加一个ApiService接口类
public interface ApiService {
public static String mBaseUrl = "http://10.0.2.2:8080/web-lesson3-demo/";
//获取验证码
@GET("api/validate-code")
Observable<CodeBean> getCodePicture();
@GET("api/validate-code")
Observable<ResponseBody> getCodePicture2();
//登录接口
@POST("api/login")
Observable<ResponseBody> loginApi(@Body RequestBody body);
//识别脸部照片
@POST("api/ai-face")
@Multipart
Observable<ResponseBody> uploadFacePhoto2(@Part MultipartBody.Part part, @Part("token") RequestBody token);
//识别脸部照片
@POST("api/ai-face")
@Multipart
Observable<FaceBean> uploadFacePhoto(@Part MultipartBody.Part part, @Part("token") RequestBody token);
}
人脸识别activity
public class FaceDetectionActivity extends BaseActivity<ActivityFaceDetectionBinding> {
private static final int REQUEST_CODE = 10000;//权限
private static final int TAKE_PHOTO = 11;// 拍照
private static final int LOCAL_CROP = 13;// 本地图库
public final String TAG = this.getClass().getSimpleName();
String currentFileUrl = "";
private FaceAdapter faceAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
faceAdapter = new FaceAdapter(this);
//android版本在6.0以上
if (Build.VERSION.SDK_INT >= 23) {
System.out.println("版本正确");
checkPermission();
} else {
System.out.println("版本过低");
}
binding.btnChoosePicture.setOnClickListener(view -> getPhoto());
binding.btnIdentifyPicture.setOnClickListener(view -> identifyFacePhoto());
binding.btnFaceLogout.setOnClickListener(view -> LogoutUser());
binding.ivFacepicture.setOnClickListener(view -> getPhoto());
}
private void LogoutUser() {
Hawk.delete("token");
Intent intent = new Intent(FaceDetectionActivity.this, LoginActivity.class);
startActivity(intent);
}
//获取人脸照片
private void getPhoto() {
CharSequence[] items = { "拍照", "图库" };// 裁剪items选项
// 弹出对话框提示用户拍照或者是通过本地图库选择图片
new AlertDialog.Builder(this)
.setItems(items, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
// 选择了拍照
case 0:
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, TAKE_PHOTO);
break;
// 调用系统图库
case 1:
// 创建Intent,用于打开手机本地图库选择图片
Intent intent1 = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
// 启动intent打开本地图库
startActivityForResult(intent1, LOCAL_CROP);
break;
}
}
}).show();
}
/**
* 调用startActivityForResult方法启动一个intent后,
* 可以在该方法中拿到返回的数据
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case TAKE_PHOTO:// 拍照
if (resultCode == RESULT_OK) {
final Bitmap photo = data.getParcelableExtra("data");
//将bitmap照片放入系统相册,并将照片给url
currentFileUrl = AppContext.saveImageToGallery(this, photo);
binding.ivFacepicture.setImageBitmap(photo);
Log.d(TAG, "onActivityResult: " + currentFileUrl);
}
break;
case LOCAL_CROP:// 系统图库
if (resultCode == RESULT_OK) {
Uri uri = data.getData();
binding.ivFacepicture.setImageURI(uri);
currentFileUrl = AppContext.getRealPathFromURI(this, uri);
Log.d(TAG, "onActivityResult: " + currentFileUrl);
}
break;
}
}
private void identifyFacePhoto() {
if (TextUtils.isEmpty(currentFileUrl)) {
AppContext.showToast("请先选择人脸照片");
return;
} else {
binding.progressBar.setVisibility(View.VISIBLE);
File file = new File(currentFileUrl);
MultipartBody.Part part = MultipartBody.Part.createFormData("image",
file.getName(),
RequestBody.create(MediaType.parse("image/*"),
file));
RequestBody body = RequestBody.create(MediaType.parse("text/plain"), "" + Hawk.get("token"));
NetworkApi.createService(ApiService.class)
.uploadFacePhoto2(part, body)
.compose(NetworkApi.applySchedulers(new BaseObserver<ResponseBody>() {
@Override public void onSuccess(ResponseBody responseBody) {
String result = AppContext.doJson(responseBody);
String face_list = null;
FaceBean.ResultBean faceListBean = null;
try {
JSONObject jsonObject = new JSONObject(result);
face_list = jsonObject.getString("result");
KLog.d(TAG, face_list);
Gson gson = new Gson();
faceListBean = gson.fromJson(String.valueOf(new JSONObject(face_list)), FaceBean.ResultBean.class);
} catch (JSONException e) {
e.printStackTrace();
}
if (faceListBean != null) {
showListFace(faceListBean);
// binding.tvIdentifyFaceRusult.setText(AppContext.doJson(responseBody));
} else {
AppContext.showToast("识别返回接口数据为空");
KLog.d(TAG, "识别返回接口数据为空");
binding.progressBar.setVisibility(View.GONE);
}
}
@Override public void onFailure(Throwable e) {
binding.progressBar.setVisibility(View.GONE);
KLog.d(TAG, e.toString());
AppContext.showToast("访问失败");
}
}));
}
}
//测试了一下
//展示泪飙
private void showListFace(FaceBean.ResultBean faceListBean) {
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
binding.ryFacePeople.setLayoutManager(layoutManager);
binding.ryFacePeople.setAdapter(faceAdapter);
binding.progressBar.setVisibility(View.GONE);
faceAdapter.updateFaceList(faceListBean.getFace_list());
}
private void checkPermission() {
ActivityCompat.requestPermissions(FaceDetectionActivity.this,
new String[] { Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE },
REQUEST_CODE);
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
//权限的申请结果返回
case REQUEST_CODE: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//已授权
AppContext.showToast("授权成功");
} else {
//未授权
AppContext.showToast("授权被拒绝");
}
}
}
}
@Override public void onBackPressed() {
super.onBackPressed();
finish();
}
}