人脸识别——使用谷歌Firebase-ML Kit实现

一,前期基础知识储备

1)Firebae是什么

由 Google 提供支持,基于 Google 基础架构而构建,可以自动扩缩的全面移动开发平台。

官网地址:https://firebase.google.com/

2)ML Kit是什么

Firebase提供的面向移动开发者的机器学习产品。

官网地址:https://firebase.google.com/products/ml-kit/

文档地址:https://firebase.google.com/docs/ml-kit/

机器学习套件将 Google 的机器学习技术(如 Google Cloud Vision APITensorFlow Lite 和 Android Neural Networks API)聚集到单个 SDK 中,使您可以在自己的应用中轻松使用机器学习技术。无论您是需要强大的云端处理能力、针对移动设备进行了优化的设备端模型的实时功能,还是自定义 TensorFlow Lite 模型的灵活性,机器学习套件都只需几行代码即可实现。

功能合集:

二,上代码,具体实现

在 Android 上使用机器学习套件检测人脸:https://firebase.google.com/docs/ml-kit/android/detect-faces

1)准备工作:

① 请将Firebase添加到Android项目中(如果尚未添加)。

对于人脸识别而言,需要先在Firebase控制台进行注册,用应用的包名生成一个Json文件,然后将该文件放置到项目中。

测试使用,可直接拿本示例项目的Json文件,文末给出。

② 请务必在您的项目级 build.gradle 文件的 buildscript 和 allprojects 部分添加 Google 的 Maven 代码库。

repositories {
        google()
        jcenter()
    }

... ...
allprojects {
    repositories {
        google()
        jcenter()
    }
}

③ 将 Android 版机器学习套件库的依赖项添加到您的模块(应用级)Gradle 文件(通常为 app/build.gradle):

    // ML Kit dependencies
    compile 'com.google.firebase:firebase-core:16.0.9'
    compile 'com.google.firebase:firebase-ml-vision:20.0.0'
    compile 'com.google.firebase:firebase-ml-vision-face-model:17.0.2'

2)输入图片指南:

为了使机器学习套件准确检测人脸,输入图片必须包含由足够像素数据表示的人脸。通常,要在图片中检测的每个人脸应至少为 100x100 像素。如果要检测人脸轮廓,机器学习套件需要更高的分辨率输入:每个人脸应至少为 200x200 像素。

如果您是在实时应用中检测人脸,则可能还需要考虑输入图片的整体尺寸。较小图片的处理速度相对较快,因此,为了减少延迟时间,请以较低的分辨率捕获图片(牢记上述准确性要求),并确保主体的面部在图片中占尽可能大的部分。

配置面部检测器 FirebaseVisionFaceDetectorOptions

FirebaseVisionFaceDetectorOptions options =
                        new FirebaseVisionFaceDetectorOptions.Builder()
                                .setPerformanceMode(FirebaseVisionFaceDetectorOptions.FAST)
                                .setContourMode(FirebaseVisionFaceDetectorOptions.ALL_CONTOURS)
                                .build();

② 运行面部检测器 FirebaseVisionImage

要检测图片中的人脸,请基于设备上的以下资源创建一个 FirebaseVisionImage 对象:Bitmapmedia.ImageByteBuffer、字节数组或文件。然后,将 FirebaseVisionImage 对象传递给 FirebaseVisionFaceDetector 的 detectInImage 方法。

对于人脸识别,您使用的图片尺寸应至少为 480x360 像素。如果您要实时识别人脸,以此最低分辨率捕获帧有助于减少延迟时间。

1. 通过图片创建 FirebaseVisionImage 对象

FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);

每种输入的方式都有不同,文档里有详细的阐述,可以根据自己的项目,实际选取对应的方式。

2. 获取 FirebaseVisionFaceDetector 的一个实例:

FirebaseVisionFaceDetector detector = FirebaseVision.getInstance()
        .getVisionFaceDetector(options);

3. 最后,将图片传递给 detectInImage 方法:

Task<List<FirebaseVisionFace>> result =
        detector.detectInImage(image)
                .addOnSuccessListener(
                        new OnSuccessListener<List<FirebaseVisionFace>>() {
                            @Override
                            public void onSuccess(List<FirebaseVisionFace> faces) {
                                // Task completed successfully
                                // ...
                            }
                        })
                .addOnFailureListener(
                        new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                // Task failed with an exception
                                // ...
                            }
                        });

3)获取检测到的面部的相关信息

如果人脸识别操作成功,系统会向成功侦听器传递一组 FirebaseVisionFace 对象。每个 FirebaseVisionFace 对象都代表一张在图片中检测到的面孔。对于每张面孔,您可以获取它在输入图片中的边界坐标,以及您已配置面部检测器查找的任何其他信息。

自定义“点”类,用以存储人脸识别的点位

public class MyPoint {
    public double x;
    public double y;

    public MyPoint(double x, double y){
        this.x = x;
        this.y = y;
    }

    public double getX(){
        return x;
    }

    public double getY(){
        return y;
    }

}

获取点位和这张图片,然后将点位画出来

    public Bitmap drawMlkiLandmarks(Bitmap bitmap, ArrayList<MyPoint> facePoints) {
        Log.d(TAG, "drawMlkiLandmarks: 1," + bitmap);
        Log.d(TAG, "drawMlkiLandmarks: 2," + facePoints);
        Bitmap bitmap3 = bitmap.copy(bitmap.getConfig(), true);
        Canvas canvas = new Canvas(bitmap3);
        for (int j = 0; j < facePoints.size(); j++) {
            int cx = (int) facePoints.get(j).x;
            int cy = (int) facePoints.get(j).y;
            Log.d(TAG, "drawMlkiLandmarks: " + j + ",," + cx + ",," + cy);
            paint.setStyle(Paint.Style.FILL_AND_STROKE);
            paint.setColor(Color.GREEN);
            paint.setStrokeWidth(3f);
            textPaint.setStrokeWidth(35f);
            textPaint.setColor(Color.WHITE);

            canvas.drawCircle(cx, cy, 3f, paint);
            canvas.drawText(String.valueOf(j), cx, cy, textPaint);
        }
        Log.d(TAG, "drawMlkiLandmarks: 3," + bitmap3);
        img.setImageBitmap(bitmap3);
        return bitmap3;
    }

以下是笔者的运行结果 —— 一共识别点位128个:运行在模拟器上,图片可能不够清晰。

另外,我们可以单独拿到各个点位,这样就可以对单个或多个点位进行攫取和调整,实际项目中非常方便。

 

最后给出主干代码,可以直接运行。

Activity代码:

public class StillImageActivity extends AppCompatActivity {
    private static final String TAG = "StillImageActivity";
    private ImageView img;
    private Bitmap bitmap;
    private Paint paint;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_stillimage);
        img = findViewById(R.id.img);
        imgTwo = findViewById(R.id.img_two);
        bitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.face_3);

        paint = new Paint();
        initMlkiFace(bitmap);

    }

    private volatile FirebaseVisionFaceDetector detector;

    private void initMlkiFace(final Bitmap bitmap) {
        final float scaleX = 1;
        final float scaleY = 1;
        final float transX = 0;
        final float transY = 0;
        if (bitmap != null) {
            FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap);
            if (detector == null) {
                FirebaseVisionFaceDetectorOptions options =
                        new FirebaseVisionFaceDetectorOptions.Builder()
                                .setPerformanceMode(FirebaseVisionFaceDetectorOptions.FAST)
                                .setContourMode(FirebaseVisionFaceDetectorOptions.ALL_CONTOURS)
                                .build();
                detector = FirebaseVision.getInstance().getVisionFaceDetector(options);
            }
            detector.detectInImage(image).addOnSuccessListener(new OnSuccessListener<List<FirebaseVisionFace>>() {
                @Override
                public void onSuccess(List<FirebaseVisionFace> faces) {
                    Log.d(TAG, "onSuccess: 识别成功");
                    ArrayList<MyPoint> facePoints = new ArrayList<>();
                    facePoints.clear();
                    if (faces.size() > 0) {
                        for (int i = 0; i < 1; i++) {
                            List<FirebaseVisionPoint> contour = faces.get(i).getContour(FirebaseVisionFaceContour.ALL_POINTS).getPoints();
                            for (int j = 0; j < contour.size(); j++) {
                                MyPoint myPoint = new MyPoint(contour.get(j).getX() * scaleX + transX, contour.get(j).getY() * scaleY + transY);
                                facePoints.add(myPoint);
                            }
                        }
                    }
                    drawMlkiLandmarks(bitmap, facePoints);
                    try {
                        if (detector != null) {
                            detector.close();
                            detector = null;
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    Log.d(TAG, "onFailure: 识别失败" + e);
                    ArrayList<MyPoint> facePoints = new ArrayList<>();
                    facePoints.clear();
                    drawMlkiLandmarks(bitmap, facePoints);
                    try {
                        if (detector != null) {
                            detector.close();
                            detector = null;
                        }
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                }
            });
        }
    }

    public Bitmap drawMlkiLandmarks(Bitmap bitmap, ArrayList<MyPoint> facePoints) {
        Log.d(TAG, "drawMlkiLandmarks: 1," + bitmap);
        Log.d(TAG, "drawMlkiLandmarks: 2," + facePoints);
        Bitmap bitmap3 = bitmap.copy(bitmap.getConfig(), true);
        Canvas canvas = new Canvas(bitmap3);
        for (int j = 0; j < facePoints.size(); j++) {
            int cx = (int) facePoints.get(j).x;
            int cy = (int) facePoints.get(j).y;
            Log.d(TAG, "drawMlkiLandmarks: " + j + ",," + cx + ",," + cy);
            paint.setStyle(Paint.Style.FILL_AND_STROKE);
            paint.setColor(Color.GREEN);
            paint.setStrokeWidth(3f);
            textPaint.setStrokeWidth(35f);
            textPaint.setColor(Color.WHITE);

            canvas.drawCircle(cx, cy, 3f, paint);
            canvas.drawText(String.valueOf(j), cx, cy, textPaint);
        }
        Log.d(TAG, "drawMlkiLandmarks: 3," + bitmap3);
        img.setImageBitmap(bitmap3);
        return bitmap3;
    }

}

本项目Json文件:google-services.json,注意文件名不可更改。

注意,两个package_name需要同自己的项目保持一致。

{
  "project_info": {
    "project_number": "48812919930",
    "firebase_url": "https://mlkit-a1dbd.firebaseio.com",
    "project_id": "mlkit-a1dbd",
    "storage_bucket": "mlkit-a1dbd.appspot.com"
  },
  "client": [
    {
      "client_info": {
        "mobilesdk_app_id": "1:48812919930:android:3b4e1d01e0aecbef",
        "android_client_info": {
          "package_name": "com.google.mlkit"
        }
      },
      "oauth_client": [
        {
          "client_id": "48812919930-ghfk9cm82ojhurb1uou7le4u42v10esv.apps.googleusercontent.com",
          "client_type": 1,
          "android_info": {
            "package_name": "com.google.mlkit",
            "certificate_hash": "0956e1fccbb13565a4543708cbf648a0858ffc43"
          }
        },
        {
          "client_id": "48812919930-ouugkae6qhraaf6b97h3ea2fvd187lrh.apps.googleusercontent.com",
          "client_type": 3
        },
        {
          "client_id": "48812919930-ouugkae6qhraaf6b97h3ea2fvd187lrh.apps.googleusercontent.com",
          "client_type": 3
        }
      ],
      "api_key": [
        {
          "current_key": "AIzaSyDorgdUVL_rlk8IGrX9x5IdYvAAt-sx7M0"
        }
      ],
      "services": {
        "analytics_service": {
          "status": 1
        },
        "appinvite_service": {
          "status": 2,
          "other_platform_oauth_client": [
            {
              "client_id": "48812919930-ouugkae6qhraaf6b97h3ea2fvd187lrh.apps.googleusercontent.com",
              "client_type": 3
            }
          ]
        },
        "ads_service": {
          "status": 2
        }
      }
    }
  ],
  "configuration_version": "1"
}

 

最后,使用ML Kit,不仅能够识别静态图片的点位,摄像头获取的动态帧数据流人脸的点位也可以获取到。所以在相机项目中的人脸识别也可以使用ML Kit来进行人脸识别。

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ML Kit是Google推出的一个移动端机器学习框架,可以方便地实现人脸识别和姿势检测。下面是实现人脸识别和姿势检测的详细步骤: 1. 在Android Studio中创建一个新的项目,将minSdkVersion设置为21或更高版本。 2. 在项目的build.gradle文件中添加以下依赖项: ``` dependencies { implementation 'com.google.firebase:firebase-ml-vision:24.0.3' } ``` 3. 配置Firebase ML Kit。在Firebase控制台中创建一个新的项目,并启用ML Kit API。然后将google-services.json文件下载到您的项目中。 4. 为了实现人脸识别,您需要在布局文件中添加一个SurfaceView用于显示照相机预览,并在Activity中实现相机预览和人脸检测。以下是一个简单的示例: ``` public class MainActivity extends AppCompatActivity { private CameraSource cameraSource; private CameraSourcePreview preview; private GraphicOverlay graphicOverlay; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); preview = findViewById(R.id.camera_preview); graphicOverlay = findViewById(R.id.face_overlay); // 创建一个人脸检测器 FaceDetector faceDetector = new FaceDetector.Builder(this) .setTrackingEnabled(false) .build(); // 创建一个相机源 cameraSource = new CameraSource.Builder(this, faceDetector) .setRequestedPreviewSize(640, 480) .setFacing(CameraSource.CAMERA_FACING_FRONT) .setAutoFocusEnabled(true) .setRequestedFps(30.0f) .build(); // 启动相机预览 preview.start(cameraSource); // 添加一个人脸检测器工具 FaceGraphic faceGraphic = new FaceGraphic(graphicOverlay); graphicOverlay.add(faceGraphic); // 设置人脸检测回调 faceDetector.setProcessor(new Detector.Processor<Face>() { @Override public void release() { graphicOverlay.clear(); } @Override public void receiveDetections(Detector.Detections<Face> detections) { // 获取人脸检测结果 SparseArray<Face> faces = detections.getDetectedItems(); if (faces.size() > 0) { Face face = faces.valueAt(0); // 更新人脸检测器工具 faceGraphic.update(face); } else { faceGraphic.setFace(null); } } }); } } ``` 5. 为了实现姿势检测,您需要在布局文件中添加一个ImageView用于显示姿势检测结果,并在Activity中实现姿势检测。以下是一个简单的示例: ``` public class MainActivity extends AppCompatActivity { private FirebaseVisionPoseDetector poseDetector; private ImageView poseImageView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); poseImageView = findViewById(R.id.pose_image); // 创建一个姿势检测器 poseDetector = FirebaseVision.getInstance().getPoseDetector(); // 加载要检测的图像 Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pose_image); // 创建一个FirebaseVisionImage对象 FirebaseVisionImage image = FirebaseVisionImage.fromBitmap(bitmap); // 进行姿势检测 poseDetector.detectInImage(image) .addOnSuccessListener(new OnSuccessListener<List<FirebaseVisionPose>>() { @Override public void onSuccess(List<FirebaseVisionPose> poses) { // 获取第一个姿势检测结果 FirebaseVisionPose pose = poses.get(0); // 获取姿势检测结果的角度 float leftShoulderAngle = pose.getPoseLandmark(FirebaseVisionPoseLandmark.LEFT_SHOULDER).getInFrameLikelihood(); float rightShoulderAngle = pose.getPoseLandmark(FirebaseVisionPoseLandmark.RIGHT_SHOULDER).getInFrameLikelihood(); // 根据角度更新姿势检测结果 if (leftShoulderAngle > 0.5 && rightShoulderAngle > 0.5) { poseImageView.setImageResource(R.drawable.correct_pose_image); } else { poseImageView.setImageResource(R.drawable.incorrect_pose_image); } } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // 处理姿势检测失败的情况 } }); } } ``` 这些是实现人脸识别和姿势检测的基本步骤。您可以根据您的需求进行更改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值