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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 17:09:05