https://www.faceplusplus.com.cn/
https://gitee.com/zouchengxin/analyze_face
http://39.106.207.193:8080/analyze_face.mp4
https://gitee.com/zouchengxin/analyze_face/blob/master/app/release/app-release.apk
主要用来调用face++ Detect和Beautify接口并与DetectActivity和BeautyActivity通讯
public class FaceUtils {
private String TAG="FaceUtils";
private String api_key="_XkXB2jly_0ZteVlGNxI8cT6S8XE4Gnj";
private String api_secret="guR94t2Pwg_0DKNTyt3QPe7iAQBuCtpa";
private FacePPApi faceApi;
public FaceUtils(){
faceApi=new FacePPApi(api_key,api_secret);
}
//传入图片进行人脸检测和人脸分析
public void detect_face(final AppCompatActivity activity, byte[] img){
Map<String,String> map=new HashMap<>();
map.put("return_landmark","1");
map.put("return_attributes","gender,age,smiling,headpose,facequality,blur,eyestatus,emotion,ethnicity,beauty,mouthstatus,eyegaze,skinstatus");
faceApi.detect(map,img,new IFacePPCallBack<DetectResponse>() {
@Override
public void onSuccess(DetectResponse detectResponse) {
String error = detectResponse.getError_message();
if(error!=null){
Toast.makeText(activity,error,Toast.LENGTH_LONG).show();
Log.e(TAG,error);
return;
}
System.out.println("detect:"+detectResponse.toString());
Intent intent=new Intent();
intent.setClass(activity,DetectActivity.class);
ImageResource.getInstance().setDetectResponse(detectResponse);
//intent.putExtra("data", JSONObject.toJSONString(detectResponse));
activity.startActivityForResult(intent,2);
}
@Override
public void onFailed(String s) {
Log.e(TAG, s);
}
});
}
//对图片进行美颜和美白
public void beauty_face(final AppCompatActivity activity, byte[] img){
HashMap<String, String> map = new HashMap<>();
faceApi.beautify(map, img, new IFacePPCallBack<BeautyResponse>() {
@Override
public void onSuccess(BeautyResponse beautyResponse) {
String error = beautyResponse.getError_message();
if(error!=null){
Toast.makeText(activity,error,Toast.LENGTH_LONG).show();
Log.e(TAG,error);
return;
}
String result = beautyResponse.getResult();
byte[] decode = Base64.decode(result, Base64.DEFAULT);
ImageResource.getInstance().setBeauty_img(BitmapFactory.decodeByteArray(decode,0,decode.length));
Intent intent = new Intent();
intent.setClass(activity,BeautyActivity.class);
activity.startActivityForResult(intent,3);
}
@Override
public void onFailed(String s) {
Log.e(TAG, s);
}
});
}
}
将数据填充到RecyclerView中
public class FaceAdapter extends RecyclerView.Adapter<ViewHolder> {
private List<Face> list;
private Context context;
public FaceAdapter(Context context){
this.context=context;
DetectResponse detectResponse = ImageResource.getInstance().getDetectResponse();
if(detectResponse!=null){
this.list=detectResponse.getFaces();
}
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.face_item, viewGroup,false);
ViewHolder viewHolder = new ViewHolder(view) {
@Override
public String toString() {
return super.toString();
}
};
return viewHolder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) {
View view = viewHolder.itemView;
FaceAttributes attributes = list.get(i).getAttributes();
if(attributes==null){
Toast.makeText(context,"加载失败!",Toast.LENGTH_LONG).show();
return;
}
//System.out.println("item"+jsonObject.toJSONString());
setItemListener(view,list.get(i).getFace_token());
ImageView iv = view.findViewById(R.id.iv);
TextView tv_age = view.findViewById(R.id.age);
TextView tv_beauty = view.findViewById(R.id.beauty);
TextView tv_gender = view.findViewById(R.id.gender);
String age = attributes.getAge().getValue();
String gender = attributes.getGender().getValue();
float beauty=0;
if(gender.equals("Female")){
gender="女性";
beauty= attributes.getBeauty().getFemale_score();
}else {
gender="男性";
beauty= attributes.getBeauty().getFemale_score();
}
tv_age.setText(tv_age.getText()+age);
tv_gender.setText(tv_gender.getText()+gender);
tv_beauty.setText(tv_beauty.getText()+String.valueOf(beauty));
CommonRect face_rect = list.get(i).getFace_rectangle();
Bitmap bitmap = Bitmap.createBitmap(
ImageResource.getInstance().getOrig_img()
,face_rect.getLeft()
,face_rect.getTop()
,face_rect.getWidth()
,face_rect.getHeight()
);
iv.setImageBitmap(bitmap);
}
@Override
public int getItemCount() {
return list.size();
}
private void setItemListener(View view, final String face_token){
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setClass(context,DetailActivity.class);
intent.putExtra("face_token",face_token);
context.startActivity(intent);
}
});
}
}
采用单例设计模式,管理原始图像,美颜后的图片,人脸分析后的结果,方便在其他activity中使用
//图片资源类
public class ImageResource {
private Bitmap orig_img;//原始图片
private Bitmap beauty_img;//美颜后的图片
private DetectResponse detectResponse;//人脸分析结果
private static ImageResource instance;
private ImageResource(){}
public static ImageResource getInstance(){
if(instance==null){
instance=new ImageResource();
}
return instance;
}
public void setOrig_img(Bitmap orig_img) {
this.orig_img = orig_img;
}
public Bitmap getOrig_img() {
return orig_img;
}
public Bitmap getBeauty_img() {
return beauty_img;
}
public void setBeauty_img(Bitmap beauty_img) {
this.beauty_img = beauty_img;
}
public DetectResponse getDetectResponse() {
return detectResponse;
}
public void setDetectResponse(DetectResponse detectResponse) {
this.detectResponse = detectResponse;
}
public void destory(){
orig_img=null;
beauty_img=null;
detectResponse=null;
}
}
主活动(源码中查看代码):https://gitee.com/zouchengxin/analyze_face/blob/master/app/src/main/java/com/zcx/anlayze_face/MainActivity.java
人脸分析活动(源码中查看代码):https://gitee.com/zouchengxin/analyze_face/blob/master/app/src/main/java/com/zcx/anlayze_face/DetectActivity.java
美颜分析活动(源码中查看代码):https://gitee.com/zouchengxin/analyze_face/blob/master/app/src/main/java/com/zcx/anlayze_face/BeautyActivity.java
详情活动(源码中查看代码):https://gitee.com/zouchengxin/analyze_face/blob/master/app/src/main/java/com/zcx/anlayze_face/DetailActivity.java
其他一些都是布局文件没啥好说的
最后说一下我遇到的坑,原先我想通过intent(意图)来传图片,结果报如下错误:
FAILED BINDER TRANSACTION !!! (parcel size = 14755544)
最后找到原因:Intent携带数据的大小受限Binder缓存的大小,Binder缓存的大小大约为1M,但有可能其他地方也存在缓存,所以实际大小肯定是小于1Mde的。所以传递小数据时可以用intent携带,但是大数据时就不考虑这种方法了,如果实在是必须使用传递那么可以使用一个操作类来暂存。
之后就采用单例设计模式存储图片了.完美解决问题.