OpenCV Android人脸检测已授予权限仍黑屏问题求助及免费方案咨询
基于OpenCV的安卓人脸检测应用运行黑屏问题解决方案
问题复现
开发基于OpenCV的安卓人脸检测应用,已完成Manifest相机权限声明、Java层动态权限申请逻辑,严格按教程完成全部开发步骤后,应用运行始终显示黑屏,现有检索结果未找到可行解决方案。
相关代码如下:
XML布局文件
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".third" > <org.opencv.android.JavaCameraView android:id="@+id/javaCam" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
Java类代码
package com.example.aiProject; import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; import android.os.Bundle; import android.util.Log; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import org.jetbrains.annotations.Nullable; import org.opencv.android.BaseLoaderCallback; import org.opencv.android.CameraBridgeViewBase; import org.opencv.android.JavaCameraView; import org.opencv.android.LoaderCallbackInterface; import org.opencv.android.OpenCVLoader; import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.core.MatOfRect; import org.opencv.core.Point; import org.opencv.core.Rect; import org.opencv.core.Scalar; import org.opencv.imgproc.Imgproc; import org.opencv.objdetect.CascadeClassifier; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; public class third extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener2 { private static final String TAG = "third"; JavaCameraView javaCam; File caseFile; CascadeClassifier faceDetector; private Mat mRgba, mGrey; private static final int MY_CAMERA_REQUEST_CODE = 100; int activeCamera = CameraBridgeViewBase.CAMERA_ID_BACK; static { if (OpenCVLoader.initDebug()) { Log.d(TAG, "OpenCV is intialised"); } else { Log.d(TAG, "OpenCV is not initialised"); } } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.third); // 原代码此处先判断权限,此时javaCam还未初始化,是核心错误点 javaCam = findViewById(R.id.javaCam); javaCam.setCvCameraViewListener(this); if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) { Log.d(TAG, "Permissions granted"); initializeCamera(javaCam, activeCamera); } else { Log.d(TAG, "Permission prompt"); ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, MY_CAMERA_REQUEST_CODE); } if (!OpenCVLoader.initDebug()) { OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION, this, baseCallback); } else { try { baseCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS); } catch (IOException e) { e.printStackTrace(); } } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == MY_CAMERA_REQUEST_CODE) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { Toast.makeText(this, "camera permission granted", Toast.LENGTH_LONG).show(); initializeCamera(javaCam, activeCamera); } else { Toast.makeText(this, "camera permission denied", Toast.LENGTH_LONG).show(); } } } private void initializeCamera(JavaCameraView javaCameraView, int activeCamera) { javaCameraView.setCameraPermissionGranted(); javaCameraView.setCameraIndex(activeCamera); javaCameraView.setVisibility(CameraBridgeViewBase.VISIBLE); javaCameraView.setCvCameraViewListener(this); } @Override public void onCameraViewStarted(int width, int height) { mRgba = new Mat(); mGrey = new Mat(); } @Override public void onCameraViewStopped() { mGrey.release(); mRgba.release(); } @Override public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) { mRgba = inputFrame.rgba(); mGrey = inputFrame.gray(); MatOfRect faceDetections = new MatOfRect(); // 竖屏适配 Core.flip(mRgba.t(), mRgba, 1); Core.flip(mGrey.t(), mGrey, 1); // 加非空判断避免崩溃 if(faceDetector != null){ faceDetector.detectMultiScale(mRgba, faceDetections); for (Rect rect : faceDetections.toArray()) { Imgproc.rectangle(mRgba, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(255, 0, 0)); } } return mRgba; } private final BaseLoaderCallback baseCallback = new BaseLoaderCallback(this) { @Override public void onManagerConnected(int status) throws IOException { switch (status) { case LoaderCallbackInterface.SUCCESS: { InputStream is = getResources().openRawResource(R.raw.haarcascade_frontalface_alt2); File cascadDir = getDir("cascade", Context.MODE_PRIVATE); caseFile = new File(cascadDir, "haarcascade_frontalface_alt2.xml"); FileOutputStream fos = new FileOutputStream(caseFile); byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = is.read(buffer)) != -1) { fos.write(buffer, 0, bytesRead); } fos.close(); is.close(); faceDetector = new CascadeClassifier(caseFile.getAbsolutePath()); if (faceDetector.empty()) { faceDetector = null; } else cascadDir.delete(); javaCam.enableView(); } break; default: { super.onManagerConnected(status); } break; } super.onManagerConnected(status); } }; }
Manifest配置文件
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.aiProject"> <uses-permission android:name="android.permission.CAMERA"/> <uses-feature android:name="android.hardware.camera" /> <queries> <intent> <action android:name="android.media.action.IMAGE_CAPTURE" /> </intent> </queries> <application android:allowBackup="true" android:icon="@drawable/logo_icon" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.AIPROJECT"> <activity android:name=".third" android:screenOrientation="portrait" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <supports-screens android:resizeable="true" android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:anyDensity="true" /> </manifest>
黑屏问题修复方案
- 核心问题修复:将
findViewById获取javaCam实例的代码移到权限判断逻辑之前,原代码权限判断通过后调用initializeCamera时javaCam为null,初始化完全失效。 - 布局修复:原XML布局中
ConstraintLayout标签末尾缺失闭合尖括号>,补上避免布局加载异常。 - 崩溃防护:在
onCameraFrame的人脸检测逻辑前加faceDetector非空判断,避免级联器加载失败导致应用崩溃。 - 冗余逻辑清理:可删除onCreate中重复的OpenCV初始化判断,静态代码块已经完成初始化校验,减少不必要的加载逻辑。
免费高并发人脸检测方案推荐
- 移动端场景:使用MTCNN安卓离线实现,检测准确率和速度远优于OpenCV Haar级联器,支持批量人脸检测,完全免费无接口调用限制。
- 服务端大数据量场景:使用YOLOv8-face开源模型本地部署推理,支持高并发检测,精度高速度快,无需调用第三方付费接口。
- 端侧轻量场景:使用百度开源的PaddlePaddle轻量人脸检测预训练模型,部署成本低,适配中低端设备,完全免费。
内容的提问来源于stack exchange,提问作者G.asma
相关产品推荐
相关产品推荐

