【发布时间】:2018-12-20 08:49:30
【问题描述】:
我正在尝试跨多个图像创建面部交换的实现。这些图像不是从相机拍摄的。它们是设备上的.jpg 文件。
我需要使用 Google 的人脸检测 API 提取人脸图像的一部分。为此,我扩展了 ImageView:
public class FaceExtractorImageView extends ImageView {
Bitmap image;
Bitmap origImage;
Context context;
FaceDetector detector;
SparseArray<Face> faces;
List<Rect> faceRects;
boolean changed = false;
Face selectedFace;
public FaceExtractorImageView(Context context) {
super(context);
this.context = context;
detector = new FaceDetector.Builder(context)
.setProminentFaceOnly(false)
.setLandmarkType(FaceDetector.ALL_LANDMARKS)
.build();
faceRects = new ArrayList<>();
//The other constructors do the exact same thing.
}
@Override
public void setImageBitmap(final Bitmap img){
image = img;
selectedFace = null;
if(!changed)
origImage = img;
changed =true;
super.setImageBitmap(img);
faces = detector.detect(new Frame.Builder().setBitmap(image).build());
faceRects.clear();
for(int i=0;i<faces.size();i++)
faceRects.add(getFaceRect(i));
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
selectedFace = null;
switch(event.getAction()){
case MotionEvent.ACTION_UP:
for(int i=0;i<faceRects.size();i++)
if(faceRects.get(i) {
.contains((int)event.getX(),
(int)event.getY())) {
selectedFace = faces.valueAt(i);
}
invalidate();
}
return true;
}
});
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(selectedFace!=null){
Paint p = new Paint();
p.setStyle(Paint.Style.STROKE);
p.setColor(Color.RED);
canvas.drawRect(getFaceRect(selectedFace), p);
}
}
public Face getSelectedFace(){
return selectedFace;
}
public Bitmap getSelectedFaceBitmap() {
if(selectedFace==null)
return null;
int index = faces.indexOfValue(selectedFace);
return getFaceBitmapWithIndex(index);
}
//Returns Bitmap of face with index @index form the currently set image
public Bitmap getFaceBitmapWithIndex(int index) {
return getFaceBitmapWithIndex(image, index);
}
//Returns Bitmap of face with index @index form image @src
public Bitmap getFaceBitmapWithIndex(Bitmap src, int index) {
Rect r = getFaceRect(index);
Bitmap created = Bitmap.createBitmap(src, r.left, r.top, r.width(), r.height());
ImageView v = new ImageView(context);
v.setImageBitmap(created);
//new AlertDialog.Builder(context).setView(v).create().show();
return created;
}
public Rect getFaceRect(Face face){
Rect r= new Rect();
//The constant values used below are for cropping the original image.
r.left = (int) face.getPosition().x + (int) face.getWidth() / 20;
r.top = (int) face.getPosition().y + (int) face.getHeight() / 4;
r.right = r.left + (int) (face.getWidth() * 5.75 / 10);
r.bottom = r.top + (int) (face.getHeight() * 3 / 5);
return r;
}
//Get rect for face at index @index of image @img
public Rect getFaceRect(int index){
Face face = faces.valueAt(index);
if(face==null) {
Log.e("Face not found", "The image in the view does not have a face with index "+index);
return null;
}
return getFaceRect(face);
}
}
上面的代码做了以下事情:
当 View 被触摸时,它会检测触摸是否在 图片。如果是,则使用以下方法在脸上绘制一个裁剪框
invalidate()。vision API给出的
Rect使用方法裁剪getFaceRect()。人脸的位图由方法给出
getFaceBitmapWithIndex(),如果有则需要索引 图像中的多个面孔。否则,索引为 0。
问题:
我在获取人脸位图时使用的Rect 是getFaceRect() 给出的那个。但是,我无法获得正确的区域。总有一些偏移。
图片说明情况:
Rect 由 Vision API 提供:
Rect 由getFaceRect() 生成。当调用invalidate() 时,这也会在onDraw() 中绘制。
调用getFaceBitmapWithIndex()时得到的区域:
我在这里遗漏了一些非常简单的东西,但我无法弄清楚那是什么。任何帮助将不胜感激。
【问题讨论】:
标签: java android image image-processing