-
读取图片的旋转的角度
-
@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 apiSecret,
@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 onError(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) {
最后
这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。
相信它会给大家带来很多收获:
当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。
- 无论你现在水平怎么样一定要 持续学习 没有鸡汤,别人看起来的毫不费力,其实费了很大力,这四个字就是我的建议!!!
- 我希望每一个努力生活的IT工程师,都会得到自己想要的,因为我们很辛苦,我们应得的。
当我们在抱怨环境,抱怨怀才不遇的时候,没有别的原因,一定是你做的还不够好!
幅有限,这里以图片的形式给大家展示一部分。
相信它会给大家带来很多收获:
[外链图片转存中…(img-V9CaarOg-1716042834444)]
当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。
- 无论你现在水平怎么样一定要 持续学习 没有鸡汤,别人看起来的毫不费力,其实费了很大力,这四个字就是我的建议!!!
- 我希望每一个努力生活的IT工程师,都会得到自己想要的,因为我们很辛苦,我们应得的。
当我们在抱怨环境,抱怨怀才不遇的时候,没有别的原因,一定是你做的还不够好!