Android人脸识别app——基于Face,kotlin语法糖

<provider

android:name=“android.support.v4.content.FileProvider”

android:authorities=“com.chaochaowu.facedetect.provider”

android:exported=“false”

android:grantUriPermissions=“true”>

<meta-data

android:name=“android.support.FILE_PROVIDER_PATHS”

android:resource="@xml/file_paths" />

拍照之后从文件中读取照片,我们可以得到一个 BitMap 对象。这里就有一个很大的坑,如果手机是三星的话,照片从文件里读出来,最后得到的照片会被旋转 90°!!!,这个贼坑啊,调了我好久,以为是自己手机的故障,后来网上查了一下,也请教了一下前辈,原来三星的手机都有这个问题,所以说我们要对文件中取出来的照片进行一下处理。

/**

  • 读取图片的旋转的角度

  • @param path 图片绝对路径

  • @return 图片的旋转角度

*/

public static int getBitmapDegree(String path) {

int degree = 0;

try {

// 从指定路径下读取图片,并获取其EXIF信息

ExifInterface exifInterface = new ExifInterface(path);

// 获取图片的旋转信息

int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,

ExifInterface.ORIENTATION_NORMAL);

switch (orientation) {

case ExifInterface.ORIENTATION_ROTATE_90:

degree = 90;

break;

case ExifInterface.ORIENTATION_ROTATE_180:

degree = 180;

break;

case ExifInterface.ORIENTATION_ROTATE_270:

degree = 270;

break;

default:

degree = 0;

break;

}

} catch (IOException e) {

e.printStackTrace();

}

return degree;

}

/**

  • 将图片按照某个角度进行旋转

  • @param bm 需要旋转的图片

  • @param degree 旋转角度

  • @return 旋转后的图片

*/

public static Bitmap rotateBitmapByDegree(Bitmap bm, int degree) {

Bitmap returnBm = null;

// 根据旋转角度,生成旋转矩阵

Matrix matrix = new Matrix();

matrix.postRotate(degree);

try {

// 将原始图片按照旋转矩阵进行旋转,并得到新的图片

returnBm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);

} catch (OutOfMemoryError | Exception e) {

e.printStackTrace();

}

if (returnBm == null) {

returnBm = bm;

}

if (bm != returnBm) {

bm.recycle();

}

return returnBm;

}

封装了两个方法,依次调用可以解决三星手机照片的问题。两个方法主要的工作就是,得到取出来的照片被旋转的角度,然后再将角度旋转回去,就可以得到原来的照片。因为并不是所有的手机在获取照片时,照片都会被旋转,所以得先判断一下照片有没有被旋转,再决定是否需要将它旋转调整。

行,这样最后就获得到了正确的 BitMap 照片,可以进行下一步了。

传照片获取数据

传照片获取数据,主要是运用了 Retrofit 和 RxJava 的封装。请求的参数可以参考 Face++ 的官方文档。

/**

  • retrofit 面部识别请求的网络服务

  • @author chaochaowu

*/

public interface FaceppService {

/**

  • @param apikey

  • @param apiSecret

  • @param imageBase64

  • @param returnLandmark

  • @param returnAttributes

  • @return

*/

@POST(“facepp/v3/detect”)

@FormUrlEncoded

Observable getFaceInfo(@Field(“api_key”) String apikey,

@Field(“api_secret”) String apiSec

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享

ret,

@Field(“image_base64”) String imageBase64,

@Field(“return_landmark”) int returnLandmark,

@Field(“return_attributes”) String returnAttributes);

}

照片需要进行 base64 转码后上传至服务器,封装了一个照片base64转码方法。

public static String base64(Bitmap bitmap){

ByteArrayOutputStream baos = new ByteArrayOutputStream();

bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);

byte[] bytes = baos.toByteArray();

return Base64.encodeToString(bytes, Base64.DEFAULT);

}

处理完成之后就可以进行网络请求获取数据。

@Override

public void getDetectResultFromServer(final Bitmap photo) {

String s = Utils.base64(photo);

faceppService.getFaceInfo(BuildConfig.API_KEY, BuildConfig.API_SECRET, s, 1, “gender,age,smiling,emotion,beauty”)

.subscribeOn(Schedulers.io())

.observeOn(AndroidSchedulers.mainThread())

.subscribe(new Observer() {

@Override

public void onSubscribe(Disposable d) {

mView.showProgress();

}

@Override

public void onNext(FaceppBean faceppBean) {

handleDetectResult(photo,faceppBean);

}

@Override

public void one rror(Throwable e) {

mView.hideProgress();

}

@Override

public void onComplete() {

mView.hideProgress();

}

});

}

Face++ 服务器会对我们上传的照片进行处理,分析照片中的人脸信息,并以 json 形式返回,返回的数据将被放入我们定义的bean类中。

/**

  • 面部识别结果的bean

  • @author chaochaowu

*/

public class FaceppBean {

/**

  • image_id : Dd2xUw9S/7yjr0oDHHSL/Q==

  • request_id : 1470472868,dacf2ff1-ea45-4842-9c07-6e8418cea78b

  • time_used : 752

  • faces : [{“landmark”:{“mouth_upper_lip_left_contour2”:{“y”:185,“x”:146},“contour_chin”:{“y”:231,“x”:137},“right_eye_pupil”:{“y”:146,“x”:205},“mouth_upper_lip_bottom”:{“y”:195,“x”:159}},“attributes”:{“gender”:{“value”:“Female”},“age”:{“value”:21},“glass”:{“value”:“None”},“headpose”:{“yaw_angle”:-26.625063,“pitch_angle”:12.921974,“roll_angle”:22.814377},“smile”:{“threshold”:30.1,“value”:2.566890001296997}},“face_rectangle”:{“width”:140,“top”:89,“left”:104,“height”:141},“face_token”:“ed319e807e039ae669a4d1af0922a0c8”}]

*/

private String image_id;

private String request_id;

private int time_used;

private List faces;

…显示部分内容

bean 类中有人脸识别得到的 性别、年龄、颜值、情绪等信息,还有每张人脸在照片中的坐标位置。接下来的工作就是对这些数据进行处理。

获取信息后的数据处理

数据的处理主要就两件事,一个是将数据以文字的形式展现,这个很简单,就不介绍了,还有一个就是将人脸在照片中标示出来,这个需要对 BitMap 进行处理,利用数据中人脸在照片中的坐标位置,我们用方框将人脸标识出来。

private Bitmap markFacesInThePhoto(Bitmap bitmap, List<FaceppBean.FacesBean> faces) {

Bitmap tempBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);

Canvas canvas = new Canvas(tempBitmap);

Paint paint = new Paint();

paint.setColor(Color.RED);

paint.setStyle(Paint.Style.STROKE);

paint.setStrokeWidth(10);

for (FaceppBean.FacesBean face : faces) {

FaceppBean.FacesBean.FaceRectangleBean faceRectangle = face.getFace_rectangle();

int top = faceRectangle.getTop();

int left = faceRectangle.getLeft();

int height = faceRectangle.getHeight();

上一篇:「存图方式」学习笔记


下一篇:Numpy实现Regression