如何在firebase mlkit中正确对齐面部轮廓?

Posted

技术标签:

【中文标题】如何在firebase mlkit中正确对齐面部轮廓?【英文标题】:how to align face contour properly in firebase mlkit? 【发布时间】:2019-05-18 15:25:19 【问题描述】:

我看到了很多例子,并尝试创建一个面部轮廓应用程序,一切都按预期工作,但无论出于何种原因,这些点都没有与实际面部对齐。

这是我的活动代码

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <com.otaliastudios.cameraview.CameraView
        android:id="@+id/cvv"
        android:layout_
        android:layout_
        app:cameraFacing="front"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" >

    <com.kirtu.simpletexts.texts.OverlayView
        android:id="@+id/overlayView"
        android:layout_
        android:layout_
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:layout_alignParentBottom="true" />
    </com.otaliastudios.cameraview.CameraView>
</android.support.constraint.ConstraintLayout>

这里是主要的活动代码

public class filter extends AppCompatActivity 
    int previewh,previeww;
    CameraView cv;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.filter);
        cv = findViewById(R.id.cvv);
        cv.setLifecycleOwner(this);
        cv.start();
        final OverlayView ov = findViewById(R.id.overlayView);
        View decorView = getWindow().getDecorView();
        int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_FULLSCREEN;
        decorView.setSystemUiVisibility(uiOptions);
        FirebaseVisionFaceDetectorOptions op =new FirebaseVisionFaceDetectorOptions.Builder()
                .setContourMode(FirebaseVisionFaceDetectorOptions.ALL_CONTOURS)
                .build();
        final FirebaseVisionFaceDetector detector= FirebaseVision.getInstance().getVisionFaceDetector(op);
        cv.addFrameProcessor(new FrameProcessor() 
            @Override
            public void process(@NonNull Frame frame) 
                if(frame.getSize() != null)
                
                    int rotation = frame.getRotation()/ 90;
                    if(rotation/2 == 0)
                    
                        previewh = cv.getPreviewSize().getHeight();
                        previeww = cv.getPreviewSize().getWidth();
                        //Log.d("texts", "process: "+cv.getPreviewSize().getWidth()+"  "+cv.getPreviewSize().getHeight());
                    else
                    
                        previewh = cv.getPreviewSize().getWidth();
                        previeww = cv.getPreviewSize().getHeight();
                        //Log.d("texts", "process: "+cv.getPreviewSize().getWidth()+"  "+cv.getPreviewSize().getHeight());
                    
                    FirebaseVisionImageMetadata metadata = new FirebaseVisionImageMetadata.Builder()
                            .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21)
                            .setWidth(frame.getSize().getWidth())
                            .setHeight(frame.getSize().getHeight())
                            .setRotation(rotation)
                            .build();
                    FirebaseVisionImage fvi = FirebaseVisionImage.fromByteArray(frame.getData(),metadata);
                    final FirebaseVisionFace[] fc = new FirebaseVisionFace[1];
                    detector.detectInImage(fvi).addOnSuccessListener(new OnSuccessListener<List<FirebaseVisionFace>>() 
                        @Override
                        public void onSuccess(List<FirebaseVisionFace> firebaseVisionFaces) 
                           for(FirebaseVisionFace f : firebaseVisionFaces)
                                
                                    ov.previewh = previewh;
                                    ov.previeww = previeww;
                                    ov.face = f;
                                    ov.invalidate();
                                

                        
                    ).addOnFailureListener(new OnFailureListener() 
                        @Override
                        public void onFailure(@NonNull Exception e) 

                        
                    );
                
            
        );
    

    @Override
    protected void onResume() 
        super.onResume();
        cv.start();
    

    @Override
    protected void onPause() 
        super.onPause();
        cv.stop();
    

    @Override
    protected void onDestroy() 
        super.onDestroy();
        cv.destroy();
    

这是覆盖代码

public class OverlayView extends View 

    public int previewh;
    public int previeww;
    public FirebaseVisionFace face;
    public Rect rect;
    private float widthScaleFactor = 1.0f;
    private float heightScaleFactor = 1.0f;
    Context c;
    Bitmap draw = BitmapFactory.decodeResource(getResources(),R.drawable.pimg);


    public OverlayView(Context context, AttributeSet attr) 
        super(context,attr);
        this.c = context;
        this.postInvalidate();

    

    @Override
    protected void onDraw(Canvas canvas) 
        super.onDraw(canvas);
        if(face!= null && canvas != null && previewh != 0 && previeww != 0)
        
            widthScaleFactor = getWidth()/previeww;
            heightScaleFactor = getHeight()/previewh;
            float maxx = 0;
            float minx = 10000;
            float maxy = 0;
            float miny = 10000;
            List<FirebaseVisionPoint> facce3= face.getContour(FirebaseVisionFaceContour.ALL_POINTS).getPoints();
            for(FirebaseVisionPoint f : facce3)
            
                Paint p1 = new Paint();
                p1.setStyle(Paint.Style.FILL);
                p1.setColor(Color.GREEN);
                p1.setStrokeWidth(5);
                canvas.drawPoint(translateX(f.getX()+50),translateY(f.getY()+50),p1);
            


            maxx = translateX(maxx);
            minx = translateX(minx);
            maxy = translateY(maxy);
            miny = translateY(miny);
            //Log.d("texts", "onDraw: "+maxx+"  "+minx+" "+maxy+"  "+miny);
            Rect r1 = new Rect(Math.round(maxx),Math.round(miny),Math.round(minx),Math.round(maxy));

        
    

    private float translateX(Float x) 
        return getWidth()-scaleX(x);
    

    private float scaleX(Float x) 
        return x*widthScaleFactor;
    

    private float translateY(Float x) 
        Resources resources = c.getResources();
        int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
        return (scaleY(x)+resources.getDimensionPixelSize(resourceId));
    

    private float scaleY(Float x)  return x*heightScaleFactor; 

我尝试通过添加一些值来调整 X 和 Y 值,但结果发现其中一侧没有被点覆盖

可以做些什么来使它在所有方面都正确对齐。

【问题讨论】:

您是否为分析仪设置了分辨率和纵横比? 【参考方案1】:

您可以在官方 firebase/quickstart-android 的repository 上查看GraphicOverlay.java:

 /**
 * Adjusts the x coordinate from the preview's coordinate system to the view coordinate system.
 */
public float translateX(float x) 
  if (overlay.facing == CameraSource.CAMERA_FACING_FRONT) 
    return overlay.getWidth() - scaleX(x);
   else 
    return scaleX(x);
  


/**
 * Adjusts the y coordinate from the preview's coordinate system to the view coordinate system.
 */
public float translateY(float y) 
  return scaleY(y);

另外,人脸识别官方文档:Detect Faces with MK Kit on Android。

【讨论】:

以上是关于如何在firebase mlkit中正确对齐面部轮廓?的主要内容,如果未能解决你的问题,请参考以下文章

MLKit 旋转面部图像使其笔直(iOS 和 Android)

Firebase ML Kit 无法检测到人脸

使用 MLKit ios swift 尝试化妆

MLKit Firebase android - 如何将 FirebaseVisionFace 转换为图像对象(如位图)?

react-native-firebase-mlkit textRecognizerProcessImage 不是函数

Firebase MLKit 眼睛轮廓 getPoints