OpenCV之级联分类器训练与使用(一) Haar与LBP级联分类器原理_图像视频中人脸检测

概述:
    级联分类器原理
    视频文件与相机中帧图像处理
    级联分类器的使用
    CascadeClassifier与XML文件结构
    视频中人脸和眼睛的检测与跟踪,人脸检测比检测到后的人脸跟踪算法要耗时的
    级联分类器的训练(HAAR/LBP)

Haar 特征与LBP特征
级联分类器原理,    不光是人脸检测,只要是有明显特征的对象,都能通过此方式训练,检测
    Viola和Jones – 2001在CVPR提出
    一种实时对象(人脸)检测框架
    算法,训练速度非常慢,检测速度非常快
    5000个正向人脸样本与300万个非人脸负样本数据
    精准度非常高
OpenCV中级联分类器使用- CascadeClassifier

AdaBoost(自适应分类器)
弱分类器 – weak classifier = Feature
强分类器 – 多个弱分类器的线性组合
级联分类器 – 多个强分类器组合
这里写图片描述

代码: 相机预览中检测人脸

    #include "../common/common.hpp"

    static CascadeClassifier face_cascader; // 级联分类检测器
    static CascadeClassifier eye_cascader;
    static String facefile = "project/workspace_vs/OpenCV310Sources_contrib/install/etc/haarcascades/haarcascade_frontalface_alt.xml"; // 训练好了的人脸数据
    static String eyefile = "project/workspace_vs/OpenCV310Sources_contrib/install/etc/haarcascades/haarcascade_eye.xml";

    void main(int argc, char** argv) 
    {
        if (!face_cascader.load(getCVImagesPath(facefile))) // 加载训练的数据
        {
            printf("could not load face feature data...\n");
        }
        if (!eye_cascader.load(getCVImagesPath(eyefile)))
        {
            printf("could not load eye feature data...\n");
        }
        VideoCapture capture(0); // 相机预览,参数 0 是只有一个摄像头的时候传,更具体的去看源代码注释
        Mat frame; // 每一帧图像
        Mat gray;
        vector<Rect> faces; // 保存检测到的人脸
        vector<Rect> eyes; // 保存检测到的人眼
        while (capture.read(frame)) // 从相机中读取每一帧数据
        {
            cvtColor(frame, gray, COLOR_BGR2GRAY);
            equalizeHist(gray, gray); // 直方图均衡化,提升对比度,提升图像特征提取的准确率
            face_cascader.detectMultiScale(gray, faces, 1.2, 3, 0, Size(30, 30)); // 在不同尺度空间检测,尺度空间比例不要设置太大,否则可能漏掉脸
            for (size_t t = 0; t < faces.size(); t++) 
            {
                Rect roi;
                roi.x = faces[static_cast<int>(t)].x;
                roi.y = faces[static_cast<int>(t)].y;
                roi.width = faces[static_cast<int>(t)].width;
                roi.height = faces[static_cast<int>(t)].height / 2; // 眼睛在人脸的上半部分
                Mat faceROI = frame(roi); // 在每帧数据中截取人脸框的上半部分,再做人眼检测,减少检测数据,提高速度
                eye_cascader.detectMultiScale(faceROI, eyes, 1.2, 3, 0, Size(20, 20)); // 检测人眼
                for (size_t k = 0; k < eyes.size(); k++) 
                {
                    Rect rect; // 由于是在人脸框内检测人眼,所以需要在整帧数据上重新定位人眼眶的位置
                    rect.x = faces[static_cast<int>(t)].x + eyes[k].x;
                    rect.y = faces[static_cast<int>(t)].y + eyes[k].y;
                    rect.width = eyes[k].width;
                    rect.height = eyes[k].height;
                    rectangle(frame, rect, Scalar(0, 255, 0), 2, 8, 0);
                }
                rectangle(frame, faces[static_cast<int>(t)], Scalar(0, 0, 255), 2, 8, 0); // 绘制人脸框
            }
            imshow("camera4-2", frame);
            if (waitKey(30) == 27)  // 间隔30毫秒获取一帧数据,esc推出
            {
                break;
            }
        }

        waitKey(0);
    }

android代码: 图像中检测人脸

@BindView(R.id.iv_cv4_2_input) ImageView mInputIv;
@BindView(R.id.iv_cv4_2_equalize) ImageView mEqualizeIv;
@BindView(R.id.iv_cv4_2_detect) ImageView mDetectIv;
private Bitmap mInputBmp;
private Bitmap mEqualizeBmp;
private Bitmap mDetectBmp;
private Mat mInputMat = new Mat();
private Mat mGrayMat = new Mat();
private Mat mEqualizeMat = new Mat();
private Mat mDetectMat = new Mat();
private CascadeClassifier mFaceCascader = new CascadeClassifier();// 级联分类检测器

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_cv4_2);
    mUnbinder = ButterKnife.bind(this);

    //input
    mInputBmp = CV310Utils.getBitmapFromAssets(this, "opencv/images/test1_3.png");
    mInputIv.setImageBitmap(mInputBmp);
    Utils.bitmapToMat(mInputBmp, mInputMat);
    initBitmaps(mInputBmp);

    //转灰度,直方图均衡化
    Imgproc.cvtColor(mInputMat, mGrayMat, Imgproc.COLOR_BGR2GRAY);
    long start = System.currentTimeMillis();
    Imgproc.equalizeHist(mGrayMat, mEqualizeMat); // 直方图均衡化,提升对比度,提升图像特征提取的准确率
    LogUtils.d("mydebug---", "1 time : "+(System.currentTimeMillis()-start)); // 0
    CV310Utils.mat2bitmapAndShowInIv(mEqualizeMat, mEqualizeBmp, mEqualizeIv);

    //人脸检测
    String sdPath = CV310Utils.asset2SDcard(this, "opencv/etc/haarcascades/haarcascade_frontalface_alt.xml",
            SDCardStoragePath.DEFAULT_OPENCV_CASCADE_HAAR, "haarcascade_frontalface_alt.xml");// 训练好了的人脸数据,从assets转存到sdcard
    boolean isLoad = mFaceCascader.load(sdPath);
    LogUtils.d("mydebug---", "isLoad="+isLoad+", sdPath="+sdPath);
    if (isLoad) {
        mInputMat.copyTo(mDetectMat);
        MatOfRect faces = new MatOfRect();
        start = System.currentTimeMillis();
        // 在不同尺度空间检测,尺度空间比例不要设置太大,否则可能漏掉脸
        mFaceCascader.detectMultiScale(mEqualizeMat, faces, 1.1, 3, 0, new Size(24, 24), new Size());
        LogUtils.d("mydebug---", "2 time : "+(System.currentTimeMillis()-start)); // 96 毫秒,擦 这么快
        List<Rect> facesRect = faces.toList();
        LogUtils.d("mydebug---", "faces.size="+facesRect.size()); // 1
        for (int i = 0; i < facesRect.size(); i++) {
            //Rect rect = new Rect(200, 100, 300, 300);//起始位置x、y,宽,高
            Rect rect = facesRect.get(i);
            Scalar color = new Scalar(255, 0, 0, 255);
            //OpenCV的坐标系,原点在屏幕左上角,x朝右正,y朝下正,参数:Mat,矩形坐上点 右下点
            Imgproc.rectangle(mDetectMat, new Point(rect.x, rect.y), new Point(rect.x+rect.width, rect.y+rect.height),
                    color, 2, 8, 0);//绘制矩形到Mat,自带圆角。。
        }
        CV310Utils.mat2bitmapAndShowInIv(mDetectMat, mDetectBmp, mDetectIv);
    }
}

/*初始化bitmap*/
private void initBitmaps(Bitmap bmp){
    mEqualizeBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.RGB_565);
    mDetectBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.RGB_565);
}

效果图

这里写图片描述

猜你喜欢

转载自blog.csdn.net/huanghuangjin/article/details/81385713