当前位置: 首页 > news >正文

Android OpenCV 人脸识别 识别人脸框 识别人脸控件自定义

先看效果

        

1.下载OpenCV

        官网地址:opcv官网
        找到Android 4.10.0版本下载

        

        下载完毕 解压zip如图:

                

 2.将OpenCV-android_sdk导入项目 我这里用的最新版的Android studio

        如果是java开发 需要添加kotlin的支持。我用的studio比较新可以参考下,如果studio版本比较老 请在网上自行寻找 kotlin支持

        

        引入完成后如下

3.编写自定义javaCameraView

        
public class OpenCVCameraView extends JavaCameraView implements CameraBridgeViewBase.CvCameraViewListener2 {
    private boolean isDetecting = true;
    private CascadeClassifier faceDetector;
    private Mat mRgba;
    private Mat mGray;
    private boolean isSaving = false;
    private File cascadeFile;
    private DetectionCallback detectionCallback;
    private int[] previewSize = new int[2];
    private Scalar FACE_RECT_COLOR = new Scalar(0, 255, 0, 255); // 人脸框颜色(绿色)
    private Scalar ROI_COLOR = new Scalar(255, 0, 0, 255);       // 识别区域颜色(蓝色)
    private int frameWidth, frameHeight;
    private int centerX, centerY, radius;

    public interface DetectionCallback {
        void onFaceDetected(Bitmap bitmap);

        void onDetectionStopped();
    }


    private Bitmap bitmap = null;
    private long lastDetectionTime = 0;

    public OpenCVCameraView(Context context, AttributeSet attrs) {
        super(context, attrs);

        initFaceDetection();
    }

    public void setDetectionCallback(DetectionCallback callback) {
        this.detectionCallback = callback;
    }

    public void startDetection() {
        isDetecting = true;
        lastDetectionTime = System.currentTimeMillis();
    }

    public void stopDetection() {
        isDetecting = false;
        if (detectionCallback != null) {
            detectionCallback.onDetectionStopped();
        }
    }

    private void initFaceDetection() {
        try {
            // 加载人脸检测分类器
            InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);
            File cascadeDir = getContext().getDir("cascade", Context.MODE_PRIVATE);
            cascadeFile = new File(cascadeDir, "lbpcascade_frontalface.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();

            faceDetector = new CascadeClassifier(cascadeFile.getAbsolutePath());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onCameraViewStarted(int width, int height) {
        mRgba = new Mat();
        mGray = new Mat();
    }

    @Override
    public void onCameraViewStopped() {
        mRgba.release();
        mGray.release();
    }

    @Override
    protected boolean initializeCamera(int width, int height) {
        return super.initializeCamera(width, height);
    }

    @Override
    public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
        mRgba = inputFrame.rgba(); // 使用灰度图进行检测
        frameWidth = mRgba.cols();
        frameHeight = mRgba.rows();
        centerX = frameWidth / 2;
        centerY = frameHeight / 2;
        radius = Math.min(frameWidth, frameHeight) / 4; //调整半径
        Core.flip(mRgba, mRgba, 1); // 参数 1 表示水平翻转

        // 检测人脸
        MatOfRect faces = new MatOfRect();
        if (faceDetector != null) {
            faceDetector.detectMultiScale(mRgba, faces, 1.1, 3, 0,
                    new Size(30, 30), new Size(200, 200));
        }

        // 绘制中间圆形识别区域
//        Imgproc.circle(mRgba, new Point(centerX, centerY), radius, ROI_COLOR, 2);
        long currentTime = System.currentTimeMillis();

        // 过滤并绘制符合条件的人脸
        if (isDetecting && (currentTime - lastDetectionTime > 500)) {

            Rect[] facesArray = faces.toArray();

            for (Rect face : facesArray) {
                int faceCenterX = face.x + face.width / 2;
                int faceCenterY = face.y + face.height / 2;
                double distance = Math.sqrt(Math.pow(faceCenterX - centerX, 2) + Math.pow(faceCenterY - centerY, 2));

                // 仅处理位于圆形区域内的人脸
                if (distance <= radius) {
                    saveImageWithFace(mRgba,face);

                    Imgproc.rectangle(mRgba,
                            new Point(face.x, face.y),
                            new Point(face.x + face.width, face.y + face.height),
                            FACE_RECT_COLOR, 2);
                    if (detectionCallback != null && bitmap != null) {
                        detectionCallback.onFaceDetected(bitmap);
                    }
                }
            }
            lastDetectionTime = currentTime;
        }
        return mRgba; // 返回处理后的帧
    }

    @SuppressLint("StaticFieldLeak")
    private void saveImageWithFace(Mat rgbaMat, Rect faceRect) {
        isSaving = true;
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... voids) {
                try {
                    // 裁剪人脸区域
                    Mat faceMat = new Mat(rgbaMat, faceRect);
                    // 转换为Bitmap
                    bitmap = Bitmap.createBitmap(
                            faceMat.cols(),
                            faceMat.rows(),
                            Bitmap.Config.ARGB_8888
                    );
                    Utils.matToBitmap(faceMat, bitmap);

                    // 保存到相册
                      //saveToGallery(bitmap);

                } catch (Exception e) {
                    e.printStackTrace();
                }
                return null;
            }

            @Override
            protected void onPostExecute(Void aVoid) {
                isSaving = false;
            }
        }.execute();
    }

    public void restartDetection() {
        isDetecting = true;
        Log.d("restartDetection", "restartDetection: 重新开始检测");
    }

    private void saveToGallery(Bitmap bitmap) {

        String fileName = "Face_" + System.currentTimeMillis() + ".jpg";
        ContentValues values = new ContentValues();
        values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");

        ContentResolver resolver = getContext().getContentResolver();
        Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

        try (OutputStream out = resolver.openOutputStream(uri)) {
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
            Log.d("图片保存", "saveToGallery: " + fileName);
            //    Toast.makeText(getContext(), "保存成功: " + fileName, Toast.LENGTH_SHORT).show();
        } catch (IOException e) {
            Toast.makeText(getContext(), "保存失败", Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        }
    }

}

        openCVCameraView 包含的功能:500 毫秒检测一次人脸通过lastDatectionTIme判断,打开检测,和关闭检测 startDetection,stopDetection,还可以识别人脸后保存到相册saveToGallery,只检测区域的人脸 防止误检测

4.在layout 里使用 再初始化

        

 mOpenCvCameraView = findViewById(R.id.camera_view);
 mOpenCvCameraView.setCvCameraViewListener(mOpenCvCameraView);
 mOpenCvCameraView.setDetectionCallback(this);
 @Override
    protected void onResume() {
        super.onResume();
        if (OpenCVLoader.initDebug()) {
            //0:后置摄像头 1:前置摄像头
            mOpenCvCameraView.setCameraIndex(0);
            mOpenCvCameraView.enableView();
            mOpenCvCameraView.setCameraPermissionGranted();
        }

    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mOpenCvCameraView != null) {
            mOpenCvCameraView.disableView();
        }
    }
        activity调用需要实现OpenCVCameraView.DetectionCallback
注意不要忘了增加相机权限!!!!!!
上面代码只完成了相机的人脸识别 功能可自己更改,圆形遮挡自定义控件后续更新喜欢的话不妨点个赞有问题评论区或者私信留言

相关文章:

  • python小整数池和字符串贮存
  • Threejs实现天空盒效果
  • 前端单页应用性能优化全指南:从加载提速到极致体验
  • 《AI大模型趣味实战》智能财务助手系统配套说明:数据报表与指标手册
  • flink cdc的source数据流如何配置事件时间,如何设置时间语义,分配时间戳并生成水位线
  • JavaScript-异步和同步函数使用场景及区别-正确构建程序的核心要点
  • 3️⃣ Coze工作流基础教学(2025年全新版本)
  • 学习MySQL第七天
  • 使用Pholcus编写Go爬虫示例
  • 高数 | 用简单的话讲考研数学知识点(二重积分)
  • 是德科技KEYSIGHT校准件85039B
  • Kubernetes 集群搭建(二):搭建k8s集群 (1.28版本)
  • rustdesk折腾手记
  • Git 仓库在内网与 Gitee 间迁移及同步记录
  • 2025年客运从业资格证考试真题分享
  • laravel update报In PackageManifest.php line 122:Undefined index: name 错误的解决办法
  • 浅谈微信视频号推荐算法
  • LLM面试题八
  • 如何在大型项目中有效使用TypeScript进行类型定义?
  • [ctfshow web入门] web18
  • 网站设计网站建设网站制作/东莞快速优化排名
  • 深圳网站建设网页制作/怎么做app推广和宣传
  • 莞城营销型网站建设/搜索引擎优化seo什么意思
  • 康保网站建设/电脑培训班价目表
  • 网站论坛推广文案怎么做/软文发稿平台有哪些
  • 怎么做便民信息网站/搜索引擎推广一般包括哪些