You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native集成OpenCV Android原生模块人脸识别文件加载问题求助

React Native集成OpenCV实现人脸匹配解决方案

你加载haarcascade_frontalface_alt2.xml失败的核心原因是使用了电脑本地绝对路径——Android设备无法访问电脑文件系统,必须将分类器文件放到项目的assets目录,通过AssetManager读取。以下是完整的实现方案:

步骤1:放置分类器文件

在android/app/src/main目录下新建assets文件夹,将haarcascade_frontalface_alt2.xml放入该目录(若没有这个文件,可从OpenCV官方包的samples/data目录中获取)。

步骤2:修正并完善人脸匹配代码

替换你原有的faceRecognition方法,以下是完整可运行的代码:

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.content.res.AssetManager;
import org.opencv.android.Utils;
import org.opencv.core.Mat;
import org.opencv.core.MatOfInt;
import org.opencv.core.MatOfRect;
import org.opencv.core.Rect;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import org.opencv.face.LBPHFaceRecognizer;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.Collections;
import android.util.Base64;

@ReactMethod
public void faceRecognition(String referenceBase64, String capturedBase64, Callback errorCallback, Callback successCallback) {
    try {
        // 图片转Bitmap
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inDither = true;
        options.inPreferredConfig = Bitmap.Config.ARGB_8888;

        byte[] decodedReference = Base64.decode(referenceBase64, Base64.DEFAULT);
        Bitmap referenceBitmap = BitmapFactory.decodeByteArray(decodedReference, 0, decodedReference.length);

        byte[] decodedCaptured = Base64.decode(capturedBase64, Base64.DEFAULT);
        Bitmap capturedBitmap = BitmapFactory.decodeByteArray(decodedCaptured, 0, decodedCaptured.length);

        // 加载人脸分类器
        CascadeClassifier classifier = null;
        AssetManager assetManager = getReactApplicationContext().getAssets();
        InputStream is = assetManager.open("haarcascade_frontalface_alt2.xml");
        File cascadeDir = getReactApplicationContext().getDir("cascade", Context.MODE_PRIVATE);
        File cascadeFile = new File(cascadeDir, "haarcascade_frontalface_alt2.xml");

        FileOutputStream os = new FileOutputStream(cascadeFile);
        byte[] buffer = new byte[4096];
        int bytesRead;
        while ((bytesRead = is.read(buffer)) != -1) {
            os.write(buffer, 0, bytesRead);
        }
        is.close();
        os.close();

        classifier = new CascadeClassifier(cascadeFile.getAbsolutePath());
        if (classifier.empty()) {
            successCallback.invoke("分类器加载失败");
            return;
        }

        // Bitmap转OpenCV Mat
        Mat referenceMat = new Mat();
        Mat capturedMat = new Mat();
        Utils.bitmapToMat(referenceBitmap, referenceMat);
        Utils.bitmapToMat(capturedBitmap, capturedMat);

        // 转灰度图(Haar分类器要求输入灰度图)
        Mat referenceGray = new Mat();
        Mat capturedGray = new Mat();
        Imgproc.cvtColor(referenceMat, referenceGray, Imgproc.COLOR_BGR2GRAY);
        Imgproc.cvtColor(capturedMat, capturedGray, Imgproc.COLOR_BGR2GRAY);

        // 检测人脸
        MatOfRect referenceFaces = new MatOfRect();
        MatOfRect capturedFaces = new MatOfRect();
        classifier.detectMultiScale(referenceGray, referenceFaces);
        classifier.detectMultiScale(capturedGray, capturedFaces);

        if (referenceFaces.toArray().length == 0 || capturedFaces.toArray().length == 0) {
            successCallback.invoke("至少一张图片未检测到人脸");
        } else {
            // 提取第一张人脸区域
            Rect referenceFace = referenceFaces.toArray()[0];
            Rect capturedFace = capturedFaces.toArray()[0];

            Mat referenceFaceMat = new Mat(referenceGray, referenceFace);
            Mat capturedFaceMat = new Mat(capturedGray, capturedFace);

            // LBPH人脸匹配
            LBPHFaceRecognizer recognizer = LBPHFaceRecognizer.create();
            recognizer.train(Collections.singletonList(referenceFaceMat), new MatOfInt(0));
            
            int[] label = new int[1];
            double[] confidence = new double[1];
            recognizer.predict(capturedFaceMat, label, confidence);

            // 置信度越低匹配度越高,阈值可根据需求调整
            String result;
            if (confidence[0] < 50) {
                result = String.format("匹配成功,置信度:%.2f", confidence[0]);
            } else {
                result = String.format("匹配失败,置信度:%.2f", confidence[0]);
            }

            successCallback.invoke(result);

            // 释放资源
            referenceFaceMat.release();
            capturedFaceMat.release();
            recognizer.release();
        }

        // 释放所有Mat资源
        referenceMat.release();
        capturedMat.release();
        referenceGray.release();
        capturedGray.release();
        referenceFaces.release();
        capturedFaces.release();

    } catch (Exception e) {
        errorCallback.invoke(e.getMessage());
    }
}

关键注意事项

  • OpenCV集成:确保React Native Android模块已正确集成OpenCV for Android,可通过在android/build.gradle中添加OpenCV依赖或导入aar包实现。
  • 资源释放:OpenCV的Mat对象必须手动释放,避免内存泄漏。
  • 权限处理:若涉及相机或相册图片,需在React Native侧申请相机、存储权限(可使用react-native-permissions库)。

内容的提问来源于stack exchange,提问作者Shura Stun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 08:55:12