首页 > 代码库 > CascadeClassifier中MaskGenerator的含义与用法

CascadeClassifier中MaskGenerator的含义与用法

 使用HOGDescirptor可以实现ROI区域的检测,但是使用CascadeClassifier不能使用ROI检测,查看CascadeClassifier的类定义可以看到这样一个子类
public:
    class CV_EXPORTS MaskGenerator
    {
    public:
        virtual ~MaskGenerator() {}
        virtual cv::Mat generateMask(const cv::Mat& src)=0;
        virtual void initializeMask(const cv::Mat& /*src*/) {};
    };
    void setMaskGenerator(Ptr<MaskGenerator> maskGenerator);
    Ptr<MaskGenerator> getMaskGenerator();

    void setFaceDetectionMaskGenerator();

protected:
    Ptr<MaskGenerator> maskGenerator;

这应该是设置检测图像的MASK吧,而且比ROI好用哦,因为使用SetROI只可以设置一个区域,而不可以设置多个区域。知道了这个类的作用赶快来大展身手一下吧。因为这个类定义的是子类,而且不能传入MASK区域进行设置,这样就需要我们定义自己的MASKGenerator类产生mask

class MaskGenerator : public CascadeClassifier::MaskGenerator
// 注意必须声明为public,否则不会调用该类的中的成员函数,编译和运行的时候也不会报错,因为类默认为私有继承,参考《C/C++->类的继承与多态》
{
public:
    MaskGenerator(){
        width = 0;
        height = 0;
        mask = NULL;
    }

    ~MaskGenerator() {
        if (mask != NULL)
            cvReleaseImage(&mask);
    }
    // 根据当前图像产生mask区域
    cv::Mat generateMask(const cv::Mat& src)
    {
        width = src.cols;
        height = src.rows;
        // 关于智能指针是否需要手动释放内存有待考究,可以参考《C/C++->智能指针的使用方法》
        // 必须手动释放
        if (mask != NULL)
            cvReleaseImage(&mask);
        mask = cvCreateImage(cvSize(width, height), 8, 1);
        cvZero(mask);
        // 可以按照自己的需求设置ROI区域
        cvSetImageROI(mask, cvRect(0, 0, width/2, height/2));
        cvSet(mask, cvScalarAll(255));
        cvResetImageROI(mask);
        //cvShowImage("mask", mask);
        //cvWaitKey(0);
        return (Mat)mask;
    }
    // 对当前图像进行操作
    void initializeMask(const cv::Mat& /*src*/) {};
private:
    int width;
    int height;
    IplImage *mask;
};

在使用该MaskGenerator之前需要调用setMaskGenerator设置mask,其实就是相当于设置一个回调函数或者说回调类
CascadeClassifier *cascade = new CascadeClassifier;
cascade->load("hogcascade_pedestrians.xml");
vector<Rect> object;
Ptr<MaskGenerator> mask = new MaskGenerator;
cascade->setMaskGenerator(mask);
cascade->detectMultiScale(srcGrayImg, object);
特别提示:该方法只适合设置traincascade产生的新分类器,不适合haartrainning产生旧分类器。

下面我们来看一下该mask在目标检测的过程中是如何使用的吧
1) 在detectMultiScale函数中,进行金字塔检测之前调用initializeMask函数进行对图像的其他初始化操作
    if (!maskGenerator.empty()) {
        maskGenerator->initializeMask(image);
    }
需要注意的是在这里最好不要做缩放image的操作,因为image是需要自己外部释放的,缩放后就改变了图像的内存,释放时会出现内存泄露的情况;在initializeMask函数可以获取图像的尺寸等操作以便按照缩放比例在generateMask函数中设置mask区域

2) 金字塔检测也就是调用detectSingleScale函数中调用generateMask产生mask区域
    Mat currentMask;
    if (!maskGenerator.empty()) {
        currentMask=maskGenerator->generateMask(image);
    }
因为这里是每缩放一次图像调用一次,所以每次调用的时候image的尺寸都是发生变化的,那么我们就可以在generateMask中根据图像的尺寸产生mask区域

3) 在检测时候,滑动图像的过程中首先检测起始坐标点是否为mask区域中的点,如果该点为mask区域中的点就跳过该检测窗口,这一过程可以在CascadeClassifierInvoker的operator()函数中看到
if ( (!mask.empty()) && (mask.at<uchar>(Point(x,y))==0)) {    continue;  }

CascadeClassifier中MaskGenerator的含义与用法