切换菜单
搜索
个人笔记云
首页
java
spring
springmvc
python
使用教程
笔记管理
搜索
登录/注册
好物分享
退出
搜索
Viola-Jones人脸检测--Harr特征
2021-09-28
958
**参考视频教程download:** [**深度学习之目标检测常用算法原理+实践精讲 **](http://www.notescloud.top/goods/detail/1430) Viola-Jones人脸检测算法是第一个实时的人脸检测算法。其影响力就不用多说了,即便是现在,该算法的应用仍然非常广泛。众所周知,Viola-Jones算法分为三个部分,Harr特征和积分图,特征选择的AdaptBoost以及用于训练的Cascade模型。对于Cascade模型,它更多的表示的是一种Strategy,这可以当作一个另外的类别了,这个类别可以看作算法的一种"细节"处理,不同的人对其有不同的看法。Cascade模型主要的目的是降低训练时间,更重要的是使得分类器具有一般性,将重点放在Object和Object邻域的那些样本点。类似于这样的Strategy还有像Kalal在他的博士论文TLD中提出的Sampling Strategy和另外的一种Cascade模型,都能够有效的降低训练时间及使分类器具有一般性,这样的一些Strategy都属于Bootstrapping,也就是训练时用一些策略做出适当的引导,而不是盲目的训练所有的样本点。下面一起看看Harr怎么回事吧。 **Harr特征和积分图** **1 理论** 就我而言Harr特征是属于Regional的特征表达方法(Focus on regional information),对于一个给定的图像窗口,Harr对该窗口的表达方式是用该窗口中的不同局域部分中的灰度差来表示的。如下图所示(a)表示一个窗口I,(b)表示Harr的一个模式,(c)表示在窗口I中计算(b)模式的Harr特征值时,只有白色和黑色部分被考虑了(也就是Focus on regional information)。 [![Viola-Jones人脸检测--Harr特征_viola](images/4377/1632828397458.png "1.png")](http://s3.51cto.com/wyfs02/M01/5C/25/wKiom1UbYSSB_095AABhq_657V4642.jpg) Harr特征常用的模式有: [![Viola-Jones人脸检测--Harr特征_viola_02](images/4377/1632828397502.png "2.png")](http://s3.51cto.com/wyfs02/M01/5C/1F/wKioL1UbYp6RAoS4AABEadCe1M8371.jpg) Harr特征值的计算公式为(窗口大小N\*N): [![Viola-Jones人脸检测--Harr特征_人脸检测_03](images/4377/1632828397540.png "3.png")](http://s3.51cto.com/wyfs02/M01/5C/25/wKiom1UbYYmTqFuaAAAzkcy8L9M635.jpg) 对于给定的一个窗口和一个Harr特征模式,如果每一个特征值的计算过程中都对一个模式中的黑色部分和白色部分进行和的计算的话,那么效率就太低了,这里积分图技术就大显身手了。对于给定的一个N\*N的窗口I,其积分图计算公式如下: [![Viola-Jones人脸检测--Harr特征_人脸检测_04](images/4377/1632828397576.png "4.png")](http://s3.51cto.com/wyfs02/M00/5C/25/wKiom1UbYbLyD0vbAAAyHd0PDtY868.jpg) 于是对一个窗口图像中的一个方形内的像素求和计算方式如下: [![Viola-Jones人脸检测--Harr特征_人脸检测_05](images/4377/1632828397729.png "5.png")](http://s3.51cto.com/wyfs02/M00/5C/25/wKiom1UbYeOAnoDUAAA8mgxij6g847.jpg) 计算积分图的算法描述如下: [![Viola-Jones人脸检测--Harr特征_Harr_06](images/4377/1632828397765.png "6.png")](http://s3.51cto.com/wyfs02/M02/5C/25/wKiom1UbYhnipDujAADQDHZBBo4719.jpg)
**2 实现**
**2.1基本数据结构**
为了方便算法的实现,这里设计了一个ImgData数据结构,该结构将注意力集中在了图像的数据部分,也许是不太完善的,但目前能够满足我的需求,你也是很容易对它做一改动去满足你的需求,比如基于ImgData设计一个三通道的图像数据结构。 登录后复制 #ifndef _IMGDATA_H_ #define_IMGDATA_H_ #include
#include
/** *@ ImgDatais a template class that is used for operating only on p_w_picpath data * and simply focus on one channel right now,but this calss could be used for * constructing the 3 or more channels operationtemplate class * *@parammdata pointer pointing to p_w_picpath data *@parammrows number of rows for p_w_picpath data *@parammcols number of cols for p_w_picpath data */ template
classImgData { private: T** mdata; unsignedintmrows; unsignedintmcols; public: /** *@brief constructor function with defaultinitialization 0 * *@param rows number of rows for p_w_picpath data *@param cols number of cols for p_w_picpath data *@val initial value for p_w_picpath data, default valueis 0 */ ImgData(unsignedintrows,unsignedintcols,Tval=0) { assert(rows > 0 && cols > 0); mrows= rows; mcols= cols; mdata= newT*[mrows]; for(unsignedinti=0; i
&data){ mrows= data.rows(); mcols= data.cols(); mdata= newT*[mrows]; for(unsignedinti=0; i
&operator=(constImgData
& data) { if(mrows!= data.rows() || mcols != data.rows()){ for(unsignedinti=0; i
cwiseProduct(constImgData
& imgData) const{ assert(mrows == imgData.rows() && mcols ==imgData.cols()); ImgData
temp(imgData.rows(), imgData.cols()); T** tempData = temp.data(); T** data = imgData.data(); for(unsignedinti=0; i
**2.2 积分图相关实现**
这里提供了一个计算积分图的实现,以及提供了一个计算积分图内的一个矩形区域的和的方法。 登录后复制 #ifndef _INTEGRALIMG_H_ #define_INTEGRALIMG_H_ #include
#include"cvImgData.h" /** * @briefintegral p_w_picpath in linear time * * @paramp_w_picpath original p_w_picpath * @returnintegralImage integral p_w_picpath */ //compute an integral p_w_picpath in linear time template
void buildIntegralImage( constImgData
&p_w_picpath , ImgData
&integralImage ){ assert(p_w_picpath.rows() == integralImage.rows()); assert(p_w_picpath.cols() == p_w_picpath.cols()); intnRows = p_w_picpath.rows(); intnCols = p_w_picpath.cols(); //O(n)complexity: however no parallel should be used T** imgData = p_w_picpath.data(); T** integralImgData = integralImage.data(); for(inti = 0; i < nRows; i++) for(intj = 0; j < nCols; j++){ integralImgData[i][j]= imgData[i][j]; integralImgData[i][j]+= i > 0 ? integralImgData[i-1][j] : 0; integralImgData[i][j]+= j > 0 ? integralImgData[i][j-1] : 0; integralImgData[i][j]-= std::min(i,j) > 0 ? integralImgData[i-1][j-1] : 0; } } /** * @brief sumup the pixels in a sub-rectangle of the p_w_picpath * * @paramintegralImage its integral p_w_picpath * @param uirow index of this sub-rectangle's up left corner * @param ujcolumn index of this sub-rectangle's up left corner * @param irnumber of rows of this sub-rectangle * @param jrnumber of columns of this sub-rectangle * @returnthe sum */ template
longdoublesumImagePart( constImgData
&integralImage , intui , intuj , intir , intjr ){ //rectangle'sother pair of coordinates intdi = ui + ir- 1; intdj = uj + jr- 1; //standardoperation T** integralData = integralImage.data(); longdoublesum = integralData[di][dj]; sum-= ui > 0 ? integralData[ui-1][dj]: 0; sum-= uj > 0 ? integralData[di][uj-1]: 0; sum+= std::min(ui, uj)> 0 ? integralData[ui-1][uj-1]: 0; returnsum; } #endif
**2.3 Harr特征实现**
对于Harr特征的计算,这里实现了Viola-Jones算法中的5种基本模式。 登录后复制 #ifndef _HARR_H_ #define_HARR_H_ #include
#include
#include
#include
#include
#include
#include"cvImgData.h" #include"cvIntegralImg.h" usingnamespacestd; #defineFOLLOW_VJtrue #defineSTD_NORM_CONST1e4 #defineFLAT_THRESHOLD1 /** * @briefcompute Haar-like features with integral p_w_picpath, * mostly for training samples use. * * @paramintegralImage its integral p_w_picpath * @paramfeatures all the features from this p_w_picpath * @paramenforceShape the original Viola-Jones's proposal or more extensive definition * of rectangle features (requires significantlymore memory if disabled) */ inlineintsumOfElement(intarray[],intk){ intret = 0; for(inti=0; i
&p_w_picpath , vector
&features , boolenforceShape= true ){ if(features.size()> 0) { features.resize(0); } //integralp_w_picpath intnRows = p_w_picpath.rows(); intnCols = p_w_picpath.cols(); //firstnormalize the example, this might prove key to learning success //meanvalue floatmean = static_cast
(p_w_picpath.sum()/(float)(nRows*nCols)); p_w_picpath-= mean; floatstd = static_cast
(sqrt(p_w_picpath.cwiseProduct(p_w_picpath).sum()/(float)(nRows*nCols))); if(std< FLAT_THRESHOLD || _isnan(std)){ std= FLAT_THRESHOLD; cout<< "Find one completely flat example. Don't worry.It'll be treated as an outlier presumably."<< endl; } //fullyuse the float range p_w_picpath*= STD_NORM_CONST; p_w_picpath/= std; ImgData
integralImage(nRows, nCols); buildIntegralImage(p_w_picpath,integralImage); //twohorizontal patterns for(intportions = 2; portions < 4; portions++){ //upleft coordinate for(inti = 0; i < nRows; i++) for(intj = 0; j < nCols; j++){ //howlong can l1 be intl1MIN = portions == 2 ? 0 : 1; intl1MAX = portions == 2 ? 0 : nCols - j; //height for(intir = 1; ir <= nRows - i; ir++) for(intl1 = l1MIN; l1 <= l1MAX; l1++) for(intl2 = 1; l2 <= nCols-j-l1; l2++) for(intl3 = 1; l3 <= nCols-j-l1-l2; l3++){ //makethese lengths more intelligible intlengths[3]; lengths[0]= l1; lengths[1]= l2; lengths[2]= l3; //nowgo for the feature doublefeature = 0; if(portions== 2){ if(enforceShape&& l2 != l3) continue; feature+= (float)sumImagePart(integralImage, i, j,ir, l2); feature-= (float)sumImagePart(integralImage, i, j+l2,ir, l3); }else{ if(enforceShape&& FOLLOW_VJ && !(l1 == l3 && l1== l2)) continue; if(enforceShape&& !FOLLOW_VJ && !(l1 == l3 && l1>= l2)) continue; for(intk = 0; k < 3; k++){ intfactor = static_cast
(pow(-1.,k)); intadvance = k == 0 ? 0 : sumOfElement(lengths, k); feature+= factor*(float)sumImagePart(integralImage, i,j+advance, ir, lengths[k]); } } //store features.push_back(feature); } } } //twovertical patterns: if you go my way, only one vertical pattern for(intportions = 2; portions < 4; portions++){ //upleft coordinate for(inti = 0; i < nRows; i++) for(intj = 0; j < nCols; j++){ intl1MIN = portions == 2 ? 0 : 1; intl1MAX = portions == 2 ? 0 : nRows - i; //width for(intjr = 1; jr <= nCols-j; jr++) for(intl1 = l1MIN; l1 <= l1MAX; l1++) for(intl2 = 1; l2 <= nRows-i-l1; l2++) for(intl3 = 1; l3 <= nRows-i-l1-l2; l3++){ //makethese lengths more intelligible intlengths[3]; lengths[0]= l1; lengths[1]= l2; lengths[2]= l3; //nowgo for the feature doublefeature = 0; if(portions== 2){ if(enforceShape&& !(l2 == l3)) continue; feature+= (float)sumImagePart(integralImage, i, j,l2, jr); feature-= (float)sumImagePart(integralImage, i+l2, j,l3, jr); }else{ if(enforceShape&& FOLLOW_VJ && !(l1 == l2 && l1== l3)) continue; //if(enforceShape&& FOLLOW_VJ) if(enforceShape&& !FOLLOW_VJ) continue; for(intk = 0; k < 3; k++){ intfactor = static_cast
(pow(-1.,k)); intadvance = k == 0 ? 0 : sumOfElement(lengths, k); feature+= factor*(float)sumImagePart(integralImage,i+advance, j, lengths[k], jr); } } //store features.push_back(feature); } } } //amixed pattern for(inti = 0; i < nRows; i++) for(intj = 0; j < nCols; j++) for(inti_l1 = 1; i_l1 < nRows - i; i_l1++) for(inti_l2 = 1; i_l2 <= nRows - i - i_l1; i_l2++) for(intj_l1 = 1; j_l1 < nCols - j; j_l1++) for(intj_l2 = 1; j_l2 <= nCols - j - j_l1; j_l2++){ if(enforceShape&& !(i_l1 == i_l2 && j_l1 == j_l2)) continue; doublefeature = 0; feature+= (float)sumImagePart(integralImage, i, j,i_l1, j_l1); feature-= (float)sumImagePart(integralImage, i, j +j_l1, i_l1, j_l2); feature-= (float)sumImagePart(integralImage, i +i_l1, j, i_l2, j_l1); feature+= (float)sumImagePart(integralImage, i + i_l1,j + j_l1, i_l2, j_l2); //record features.push_back(feature); } }
reference: Yi-Qing Wang, An Analysis of the Viola-Jones Face Detection Algorithm, IPOL.
教程分类
热门视频教程
热门文章
热门书籍推荐