1

我想像 Snapchat 应用一样在相机中制作实时过滤器。此应用基于Google Vision Face Tracker

我在 FaceGraphic.java 中有以下代码:

package com.google.android.gms.samples.vision.face.facetracker;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

import com.google.android.gms.samples.vision.face.facetracker.ui.camera.GraphicOverlay;
import com.google.android.gms.vision.face.Face;
import com.google.android.gms.vision.face.Landmark;

/**
 * Graphic instance for rendering face position, orientation, and landmarks within an associated
* graphic overlay view.
*/
class FaceGraphic extends GraphicOverlay.Graphic {
    private static final float FACE_POSITION_RADIUS = 10.0f;
    private static final float ID_TEXT_SIZE = 40.0f;
    private static final float ID_Y_OFFSET = 50.0f;
    private static final float ID_X_OFFSET = -50.0f;
    private static final float BOX_STROKE_WIDTH = 5.0f;

    private static final int COLOR_CHOICES[] = {
        Color.BLUE,
        Color.CYAN,
        Color.GREEN,
        Color.MAGENTA,
        Color.RED,
        Color.WHITE,
        Color.YELLOW
    };
    private static int mCurrentColorIndex = 0;

    private Paint mFacePositionPaint;
    private Paint mIdPaint;
    private Paint mBoxPaint;

    private volatile Face mFace;
    private int mFaceId;
    private float mFaceHappiness;

    private Bitmap bitmap;
    private Bitmap sunglasses;

    FaceGraphic(GraphicOverlay overlay) {
        super(overlay);

        mCurrentColorIndex = (mCurrentColorIndex + 1) % COLOR_CHOICES.length;
        final int selectedColor = COLOR_CHOICES[mCurrentColorIndex];

        mFacePositionPaint = new Paint();
        mFacePositionPaint.setColor(selectedColor);

        mIdPaint = new Paint();
        mIdPaint.setColor(selectedColor);
        mIdPaint.setTextSize(ID_TEXT_SIZE);

        mBoxPaint = new Paint();
        mBoxPaint.setColor(selectedColor);
        mBoxPaint.setStyle(Paint.Style.STROKE);
        mBoxPaint.setStrokeWidth(BOX_STROKE_WIDTH);

        bitmap = BitmapFactory.decodeResource(getOverlay().getContext().getResources(), R.drawable.sunglasses);
        sunglasses = bitmap;

    }

    void setId(int id) {
        mFaceId = id;
    }


    /**
     * Updates the face instance from the detection of the most recent frame.  Invalidates the
     * relevant portions of the overlay to trigger a redraw.
     */
    void updateFace(Face face) {
        mFace = face;

        sunglasses = Bitmap.createScaledBitmap(bitmap, (int) scaleX(face.getWidth()),
                (int) scaleY(((bitmap.getHeight() * face.getWidth()) / bitmap.getWidth())), false);

        postInvalidate();
    }

    /**
     * Draws the face annotations for position on the supplied canvas.
     */
    @Override
    public void draw(Canvas canvas) {
        Face face = mFace;

        if (face == null) {
            return;
        }

        float x = translateX(face.getPosition().x + face.getWidth() / 2);
        float y = translateY(face.getPosition().y + face.getHeight() / 2);

        // Draws a bounding box around the face.
        float xOffset = scaleX(face.getWidth() / 2.0f);
        float yOffset = scaleY(face.getHeight() / 2.0f);
        float left = x - xOffset;
        float top = y - yOffset;
        float right = x + xOffset;
        float bottom = y + yOffset;
        canvas.drawRect(left, top, right, bottom, mBoxPaint);

        //Get the left eye to place the sunglasses over the eyes
        float eyeY = top + sunglasses.getHeight() / 2;
        for(Landmark l : face.getLandmarks()){
            if(l.getType() == Landmark.LEFT_EYE){
                eyeY = l.getPosition().y + sunglasses.getHeight() / 2;
            }
        }
        canvas.drawBitmap(sunglasses, left, eyeY, new Paint());

    }
}

我创建了在FaceTrackerActivity.java中拍照的函数:

findViewById(R.id.capture).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mCameraSource.takePicture(null, new CameraSource.PictureCallback() {

                @Override
                public void onPictureTaken(byte[] bytes) {
                    Log.d(TAG, "onPictureTaken - jpeg");
                    capturePic(bytes);
                }

                private void capturePic(byte[] bytes) {
                    try {
                        String mainpath = getExternalStorageDirectory() + separator + "MaskIt" + separator + "images" + separator;
                        File basePath = new File(mainpath);
                        if (!basePath.exists())
                            Log.d("CAPTURE_BASE_PATH", basePath.mkdirs() ? "Success": "Failed");
                        File captureFile = new File(mainpath + "photo_" + getPhotoTime() + ".jpg");
                        if (!captureFile.exists())
                            Log.d("CAPTURE_FILE_PATH", captureFile.createNewFile() ? "Success": "Failed");
                        FileOutputStream stream = new FileOutputStream(captureFile);
                        stream.write(bytes);
                        stream.flush();
                        stream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

                private String getPhotoTime(){
                    SimpleDateFormat sdf=new SimpleDateFormat("ddMMyy_hhmmss");
                    return sdf.format(new Date());
                }
            });
        }
    });

首先,打开应用程序并授予访问相机的权限,应用程序将检测面部并为其绘制位图(太阳镜)。我创建了 ID 为capture的按钮“拍照” 。

这是我的 main.xml:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/topLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:keepScreenOn="true"
    android:weightSum="1"
    android:orientation="vertical">

  <LinearLayout
      android:orientation="horizontal"
      android:layout_width="match_parent"
      android:layout_height="64dp">

    <Button
        android:text="Sunglasses"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/sun"
        android:layout_weight="1"
        tools:ignore="HardcodedText" />

    <Button
        android:text="Helmet"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/helm"
        android:layout_weight="1"
        tools:ignore="HardcodedText" />

    <Button
        android:text="Mustache"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/must"
        android:layout_weight="1"
        tools:ignore="HardcodedText" />
  </LinearLayout>
<com.google.android.gms.samples.vision.face.facetracker.ui.camera.CameraSourcePreview
      android:id="@+id/preview"
      android:layout_width="match_parent"
      android:layout_height="0dp"
      android:layout_weight="0.99"
      android:weightSum="1">
    <com.google.android.gms.samples.vision.face.facetracker.ui.camera.GraphicOverlay
        android:id="@+id/faceOverlay"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="0.79" />

</com.google.android.gms.samples.vision.face.facetracker.ui.camera.CameraSourcePreview>

  <Button
      android:id="@+id/capture"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:text="Take a Picture"
      tools:ignore="HardcodedText" />
    </LinearLayout>

如何获得在 FaceGraphic 中绘制的位图?如果我拍照,我只会得到没有位图的默认照片。我想用用户面孔和位图拍照并保存到图库中。对不起,我希望你能理解我的问题。谢谢你。

4

2 回答 2

1

您可以使用 Vision API 执行此操作,步骤如下:

  1. 在预览中设置 setDrawingCacheEnabled

    mPreview.setDrawingCacheEnabled(true)

  2. 从中获取位图

    位图drawingCache = mPreview.getDrawingCache();

  3. 使用 CameraSource.takePicture() 方法捕获图像并在其上绘制预览位图。

你可以在这里查看我的完整答案

于 2019-04-23T12:37:56.017 回答
0

因此,如果是这种情况,您想立即捕获 SurfaceView 上可用的所有内容,您可以看看这个问题, 如何从 SurfaceView 创建和保存屏幕截图?

于 2017-01-18T07:02:41.227 回答