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
相关产品推荐
相关产品推荐

