【问题标题】:ImageView bitmap offset correctionImageView 位图偏移校正
【发布时间】: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);
    }
}

上面的代码做了以下事情:

  1. 当 View 被触摸时,它会检测触摸是否在 图片。如果是,则使用以下方法在脸上绘制一个裁剪框 invalidate()

  2. vision API给出的Rect使用方法裁剪 getFaceRect()

  3. 人脸的位图由方法给出 getFaceBitmapWithIndex(),如果有则需要索引 图像中的多个面孔。否则,索引为 0。

问题: 我在获取人脸位图时使用的RectgetFaceRect() 给出的那个。但是,我无法获得正确的区域。总有一些偏移。

图片说明情况:

Rect 由 Vision API 提供:

RectgetFaceRect() 生成。当调用invalidate() 时,这也会在onDraw() 中绘制。

调用getFaceBitmapWithIndex()时得到的区域:

我在这里遗漏了一些非常简单的东西,但我无法弄清楚那是什么。任何帮助将不胜感激。

【问题讨论】:

    标签: java android image image-processing


    【解决方案1】:

    我发现了错误。事实证明,相对于 View 本身,我没有处理不同图像的不同尺寸。

    所以,我将调用super 之后的代码放在setImageBitmap 中的getViewTreeObserver().addOnGlobalLayoutListener 中,并在那里构建了一个新的DrawingCache

    @Override
    public void setImageBitmap(final Bitmap img){
        if(!changed)
            origImage = img;
    
        changed =true;
    
        super.setImageBitmap(img);
        getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                buildDrawingCache();
                image = getDrawingCache();
                selectedFace = null;
                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())) {
                                        //Toast.makeText(context, "Touched", Toast.LENGTH_LONG).show();
                                        selectedFace = faces.valueAt(i);
                                    }
                                invalidate();
                        }
                        return true;
                    }
                });
            }
        });
    }
    

    【讨论】:

      猜你喜欢
      • 2021-01-20
      • 1970-01-01
      • 2012-06-09
      • 2023-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多