使用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; }