github地址
https://github.com/sunbo-ui/faceDiscern
- 第一次自己手动集成人脸识别,期间报错不断,报错的地方很多,但记住的不多.哈哈哈,有多少写多少吧~(此项目仅在小米10上测试成功)
首先是调用照相机
- 拍照并获取缩略图,拍照并获取缩略图不需要任何权限,只需要调用相机然后获取结果即可
// android 7.0系统解决拍照的问题
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
builder.detectFileUriExposure()
- 使用http请求报错not permitted by network security policy
- 在res建立xml/network_security_config.xml'
- 以及在androidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!--默认允许所有网址使用非安全连接-->
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
<application
android:networkSecurityConfig="@xml/network_security_config"
..../>
- 开始使用照相机,
这里一开始有个bug,就是直接调用相机,这样做,onActivityResult方法返回的图像会默认被压缩一遍,使得显示到页面的图像会非常小.
/直接调用相机/
...
Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//用来打开相机的Intent
startActivityForResult(takePhotoIntent,REQ_CODE);//启动相机
...
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode==REQ_CODE&&resultCode==RESULT_OK){
/*缩略图信息是储存在返回的intent中的Bundle中的,
* 对应Bundle中的键为data,因此从Intent中取出
* Bundle再根据data取出来Bitmap*/
Bundle extras = data.getExtras();
Bitmap bitmap = (Bitmap) extras.get("data");
mPicture.setImageBitmap(bitmap);
}
}
- 改进方法,使用 intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(phoPath)));
if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
Toast.makeText(MainActivity.this, "sdcard未使用~", Toast.LENGTH_SHORT).show();
return;
}
//调用摄像头
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
phoPath = getFileName();
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(phoPath)));
startActivityForResult(intent, CAMERA_REQUEST);//跳转
--------------------
//返回结果的方法
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case CAMERA_REQUEST:
if (resultCode == Activity.RESULT_OK) {
//将保存在本地的图片取出并显示在界面上
bitmap = BitmapFactory.decodeFile(phoPath);
//将处理过的图片显示在界面上,并保存到本地
imageView.setImageBitmap(bitmap);
getImageFile();//获取图片信息,人脸识别用的
}
break;
}
}
保存图片到手机
- 添加动态权限
//动态获取权限
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE},
1);
- 保存
/**
* 保存图片到图库
*/
public void saveImageToGallery(Bitmap mBitmap) {
if (mBitmap == null) {
Toast.makeText(MainActivity.this, "还没有照片可以保存哦~", Toast.LENGTH_SHORT).show();
return;
}
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
Toast.makeText(MainActivity.this, "sdcard未使用~", Toast.LENGTH_SHORT).show();
return;
}
// 首先保存图片
File appDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsoluteFile();
if (!appDir.exists()) {
appDir.mkdir();
}
String fileName = System.currentTimeMillis() + ".jpg";
File file = new File(appDir, fileName);
try {
FileOutputStream fos = new FileOutputStream(file);
mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
Toast.makeText(MainActivity.this, "保存失败~", Toast.LENGTH_SHORT).show();
return;
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(MainActivity.this, "保存失败~", Toast.LENGTH_SHORT).show();
return;
}
// 其次把文件插入到系统图库
try {
MediaStore.Images.Media.insertImage(getApplication().getContentResolver(), file.getAbsolutePath(), fileName, null);
Toast.makeText(MainActivity.this, "保存成功~", Toast.LENGTH_SHORT).show();
} catch (FileNotFoundException e) {
Toast.makeText(MainActivity.this, "保存失败~", Toast.LENGTH_SHORT).show();
e.printStackTrace();
} // 最后通知图库更新
getApplication().sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + "")));
bitmap.recycle();
}
通过face++官方文档使用okhttp+gson来获取数据
- 一个注意点:face++需要的图片数据我选择的是image_base64,需要转成base64以及需要控制图片大小,因为系统相机返回的图像太大,就选择手动压缩拉一下
//相机返回的方法中调用过方法
public void getImageFile() {
zip();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmapZip.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] bitmapBytes = baos.toByteArray();
//转成base64设置到ImageView
image_file = Base64.encodeToString(bitmapBytes, Base64.DEFAULT);
try {
baos.flush();
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private void zip() {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; // 只获取图片的大小信息,而不是将整张图片载入在内存中,避免内存溢出
BitmapFactory.decodeFile(phoPath, options);
int height = options.outHeight;
int width = options.outWidth;
int inSampleSize = 2; // 默认像素压缩比例,压缩为原图的1/2
int minLen = Math.min(height, width); // 原图的最小边长
if (minLen > 100) { // 如果原始图像的最小边长大于100dp(此处单位我认为是dp,而非px)
float ratio = (float) minLen / 100.0f; // 计算像素压缩比例
inSampleSize = (int) ratio;
}
options.inJustDecodeBounds = false; // 计算好压缩比例后,这次可以去加载原图了
options.inSampleSize = inSampleSize; // 设置为刚才计算的压缩比例
bitmapZip = BitmapFactory.decodeFile(phoPath, options); // 解码文件
}
if (image_file == null || "".equals(image_file)) {
Toast.makeText(MainActivity.this, "请先拍个照~", Toast.LENGTH_SHORT).show();
return;
}
OkHttpClient okHttpClient = new OkHttpClient();
//2.创建一个RequestBody,可以用add添加键值对
RequestBody requestBody = new FormBody.Builder()
.add("api_key", api_key)
.add("api_secret", api_secret)
.add("return_attributes", "gender,age,beauty,skinstatus")
.add("image_base64", image_file)
.build();
//3.创建Request对象,设置URL地址,将RequestBody作为post方法的参数传入
Request request = new Request.Builder().url(url).post(requestBody).build();
//4.创建一个call对象,参数就是Request请求对象
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
runOnUiThread(new Runnable() {
@Override
public void run() {
e.printStackTrace();
Toast.makeText(MainActivity.this, "请求网络数据失败", Toast.LENGTH_SHORT).show();
}
});
}
//请求成功时调用该方法
@Override
public void onResponse(Call call, Response response) throws IOException {
runOnUiThread(new Runnable() {
@Override
public void run() {
getData(response);
}
});
}
});
- getData(response)方法则是使用实体内部类接收json数据