基于Haar特征的Adaboost级联人脸检测分类器
基于Haar特征的Adaboost级联人脸检测分类器,简称haar分类器。通过这个算法的名字,我们可以看到这个算法其实包含了几个关键点:Haar特征、Adaboost、级联。理解了这三个词对该算法基本就掌握了。
1 算法要点
Haar分类器 = Haar-like特征 + 积分图方法 + AdaBoost +级联;
Haar分类器算法的要点如下:
a) 使用Haar-like特征做检测。
b) 使用积分图(IntegralImage)对Haar-like特征求值进行加速。
c) 使用AdaBoost算法训练区分人脸和非人脸的强分类器。
d) 使用筛选式级联把分类器级联到一起,提高准确率。
2 历史
在2001年,Viola和Jones两位大牛发表了经典的《Rapid Object Detectionusing a Boosted Cascade of Simple Features》和《Robust Real-Time Face Detection》,在AdaBoost算法的基础上,使用Haar-like小波特征和积分图方法进行人脸检测,他俩不是最早使用提出小波特征的,但是他们设计了针对人脸检测更有效的特征,并对AdaBoost训练出的强分类器进行级联。这可以说是人脸检测史上里程碑式的一笔了,也因此当时提出的这个算法被称为Viola-Jones检测器。又过了一段时间,RainerLienhart和Jochen
Maydt两位大牛将这个检测器进行了扩展,最终形成了OpenCV现在的Haar分类器。
AdaBoost是Freund和Schapire在1995年提出的算法,是对传统Boosting算法的一大提升。Boosting算法的核心思想,是将弱学习方法提升成强学习算法,也就是“三个臭皮匠顶一个诸葛亮”
3 Haar特征
什么是特征,特征就是分类器的输入。把它放在下面的情景中来描述,假设在人脸检测时我们需要有这么一个子窗口在待检测的图片窗口中不断的移位滑动,子窗口每到一个位置,就会计算出该区域的特征,然后用我们训练好的级联分类器对该特征进行筛选,一旦该特征通过了所有强分类器的筛选,则判定该区域为人脸。
基于Haar特征的Adaboost级联人脸检测分类器,简称haar分类器。通过这个算法的名字,我们可以看到这个算法其实包含了几个关键点:Haar特征、Adaboost、级联。理解了这三个词对该算法基本就掌握了。
1 算法要点
Haar分类器 = Haar-like特征 + 积分图方法 + AdaBoost +级联;
Haar分类器算法的要点如下:
a) 使用Haar-like特征做检测。
b) 使用积分图(IntegralImage)对Haar-like特征求值进行加速。
c) 使用AdaBoost算法训练区分人脸和非人脸的强分类器。
d) 使用筛选式级联把分类器级联到一起,提高准确率。
2 历史
在2001年,Viola和Jones两位大牛发表了经典的《Rapid Object Detectionusing a Boosted Cascade of Simple Features》和《Robust Real-Time Face Detection》,在AdaBoost算法的基础上,使用Haar-like小波特征和积分图方法进行人脸检测,他俩不是最早使用提出小波特征的,但是他们设计了针对人脸检测更有效的特征,并对AdaBoost训练出的强分类器进行级联。这可以说是人脸检测史上里程碑式的一笔了,也因此当时提出的这个算法被称为Viola-Jones检测器。又过了一段时间,RainerLienhart和Jochen
Maydt两位大牛将这个检测器进行了扩展,最终形成了OpenCV现在的Haar分类器。
AdaBoost是Freund和Schapire在1995年提出的算法,是对传统Boosting算法的一大提升。Boosting算法的核心思想,是将弱学习方法提升成强学习算法,也就是“三个臭皮匠顶一个诸葛亮”
3 Haar特征
什么是特征,特征就是分类器的输入。把它放在下面的情景中来描述,假设在人脸检测时我们需要有这么一个子窗口在待检测的图片窗口中不断的移位滑动,子窗口每到一个位置,就会计算出该区域的特征,然后用我们训练好的级联分类器对该特征进行筛选,一旦该特征通过了所有强分类器的筛选,则判定该区域为人脸。
1 clc; 2 clear; 3 close all; 4 5 % Haar-like特征矩形计算 6 7 board = 24 % 检测窗口宽度 8 num = 24 % 检测窗口分划数 9 10 show = 1; % 1为作图 11 time = 0.001; % 作图间隔 12 13 %% 14 15 if mod(board,num)~=0 16 error('检测窗口宽度必须是分划数的整数倍') 17 else 18 delta = board/num % 滑动步进值 19 end 20 21 % Haar特征1:左白,右黑,(s,t)=(1,2) 22 23 s = 1; 24 t = 2; 25 R = s:s:floor(num/s)*s; % Haar窗口高 26 C = t:t:floor(num/t)*t; % Haar窗口宽 27 NUM = 0; % Haar特征总数 28 29 % '---- Haar特征1:左白,右黑,(s,t)=(1,2) ---' 30 for I = 1:length(R) 31 for J = 1:length(C) 32 33 r = R(I)*delta; % Haar窗口高 34 c = C(J)*delta; % Haar窗口宽 35 nr = num-R(I)+1; % 行方向移动个数 36 nc = num-C(J)+1; % 列方向移动个数 37 38 Px0 = [0 r]; % 矩形坐标初始化 39 Py0 = [0 c/2 c]; 40 for i = 1:nr 41 for j = 1:nc 42 Px = Px0+(i-1)*delta; % 滑动取点 43 Py = Py0+(j-1)*delta; 44 NUM = NUM+1; 45 46 if show 47 plot([0 board],repmat((0:delta:board)',1,2),'k'); hold on; 48 plot(repmat((0:delta:board)',1,2),[0 board],'k'); axis tight; axis square; 49 title('Haar矩形遍历演示');xlabel('x');ylabel('y'); 50 51 plot(Px,repmat(Py',1,2),'r','LineWidth',5) 52 plot(repmat(Px,2,1),repmat([Py(1) Py(end)]',1,2),'r','LineWidth',5); hold off 53 pause(time) 54 end 55 56 end 57 end 58 59 end 60 end 61 NUM 62 %% Haar特征2:上白,下黑,(s,t)=(2,1) 63 s = 2; 64 t = 1; 65 R = s:s:floor(num/s)*s; % Haar窗口高 66 C = t:t:floor(num/t)*t; % Haar窗口宽 67 NUM = 0; % Haar特征总数 68 '---- Haar特征2:上白,下黑,(s,t)=(2,1) ---' 69 for I = 1:length(R) 70 for J = 1:length(C) 71 72 r = R(I)*delta; % Haar窗口高 73 c = C(J)*delta; % Haar窗口宽 74 nr = num-R(I)+1; % 行方向移动个数 75 nc = num-C(J)+1; % 列方向移动个数 76 77 Px0 = [0 r/2 r]; % 矩形坐标初始化 78 Py0 = [0 c]; 79 for i = 1:nr 80 for j = 1:nc 81 Px = Px0+(i-1)*delta; % 滑动取点 82 Py = Py0+(j-1)*delta; 83 NUM = NUM+1; 84 if show 85 plot([0 board],repmat((0:delta:board)',1,2),'k'); hold on; 86 plot(repmat((0:delta:board)',1,2),[0 board],'k'); axis tight; axis square; 87 title('Haar矩形遍历演示');xlabel('x');ylabel('y'); 88 89 plot(repmat(Px,2,1),repmat(Py',1,length(Px)),'r','LineWidth',3); 90 plot(repmat([Px(1) Px(end)]',1,2),repmat(Py,2,1),'r','LineWidth',3); hold off 91 pause(time) 92 end 93 94 end 95 end 96 97 end 98 end 99 NUM 100 %% Haar特征3:左右白,中间黑,(s,t)=(1,3) 101 s = 1; 102 t = 3; 103 R = s:s:floor(num/s)*s; % Haar窗口高 104 C = t:t:floor(num/t)*t; % Haar窗口宽 105 NUM = 0; % Haar特征总数 106 '---- Haar特征3:左右白,中间黑,(s,t)=(1,3) ---' 107 for I = 1:length(R) 108 for J = 1:length(C) 109 110 r = R(I)*delta; % Haar窗口高 111 c = C(J)*delta; % Haar窗口宽 112 nr = num-R(I)+1; % 行方向移动个数 113 nc = num-C(J)+1; % 列方向移动个数 114 115 Px0 = [0 r]; % 矩形坐标初始化 116 Py0 = [0 c/3 c*2/3 c]; 117 for i = 1:nr 118 for j = 1:nc 119 Px = Px0+(i-1)*delta; % 滑动取点 120 Py = Py0+(j-1)*delta; 121 NUM = NUM+1; 122 123 if show 124 plot([0 board],repmat((0:delta:board)',1,2),'k'); hold on; 125 plot(repmat((0:delta:board)',1,2),[0 board],'k'); axis tight; axis square; 126 title('Haar矩形遍历演示');xlabel('x');ylabel('y'); 127 128 plot(Px,repmat(Py',1,2),'r','LineWidth',5) 129 plot(repmat(Px,2,1),repmat([Py(1) Py(end)]',1,2),'r','LineWidth',5); hold off 130 pause(time) 131 end 132 end 133 end 134 135 end 136 end 137 NUM 138 %% Haar特征4:左右白,中间黑(2倍宽度),(s,t)=(1,4) 139 s = 1; 140 t = 4; 141 R = s:s:floor(num/s)*s; % Haar窗口高 142 C = t:t:floor(num/t)*t; % Haar窗口宽 143 NUM = 0; % Haar特征总数 144 '---- Haar特征4:左右白,中间黑(2倍宽度),(s,t)=(1,4) ---' 145 for I = 1:length(R) 146 for J = 1:length(C) 147 148 r = R(I)*delta; % Haar窗口高 149 c = C(J)*delta; % Haar窗口宽 150 nr = num-R(I)+1; % 行方向移动个数 151 nc = num-C(J)+1; % 列方向移动个数 152 153 Px0 = [0 r]; % 矩形坐标初始化 154 Py0 = [0 c/4 c*3/4 c]; 155 for i = 1:nr 156 for j = 1:nc 157 Px = Px0+(i-1)*delta; % 滑动取点 158 Py = Py0+(j-1)*delta; 159 NUM = NUM+1; 160 161 if show 162 plot([0 board],repmat((0:delta:board)',1,2),'k'); hold on; 163 plot(repmat((0:delta:board)',1,2),[0 board],'k'); axis tight; axis square; 164 title('Haar矩形遍历演示');xlabel('x');ylabel('y'); 165 166 plot(Px,repmat(Py',1,2),'r','LineWidth',5) 167 plot(repmat(Px,2,1),repmat([Py(1) Py(end)]',1,2),'r','LineWidth',5); hold off 168 pause(time) 169 end 170 171 end 172 end 173 174 end 175 end 176 NUM 177 %% Haar特征5:上下白,中间黑,(s,t)=(3,1) 178 s = 3; 179 t = 1; 180 R = s:s:floor(num/s)*s; % Haar窗口高 181 C = t:t:floor(num/t)*t; % Haar窗口宽 182 NUM = 0; % Haar特征总数 183 '---- Haar特征5:上下白,中间黑,(s,t)=(3,1) ---' 184 for I = 1:length(R) 185 for J = 1:length(C) 186 187 r = R(I)*delta; % Haar窗口高 188 c = C(J)*delta; % Haar窗口宽 189 nr = num-R(I)+1; % 行方向移动个数 190 nc = num-C(J)+1; % 列方向移动个数 191 192 Px0 = [0 r/3 r*2/3 r]; % 矩形坐标初始化 193 Py0 = [0 c]; 194 for i = 1:nr 195 for j = 1:nc 196 Px = Px0+(i-1)*delta; % 滑动取点 197 Py = Py0+(j-1)*delta; 198 NUM = NUM+1; 199 200 if show 201 plot([0 board],repmat((0:delta:board)',1,2),'k'); hold on; 202 plot(repmat((0:delta:board)',1,2),[0 board],'k'); axis tight; axis square; 203 title('Haar矩形遍历演示');xlabel('x');ylabel('y'); 204 205 plot(repmat(Px,2,1),repmat(Py',1,length(Px)),'r','LineWidth',3); 206 plot(repmat([Px(1) Px(end)]',1,2),repmat(Py,2,1),'r','LineWidth',3); hold off 207 pause(time) 208 end 209 210 end 211 end 212 213 end 214 end 215 NUM 216 %% Haar特征6:上下白,中间黑(2倍宽度),(s,t)=(4,1) 217 s = 4; 218 t = 1; 219 R = s:s:floor(num/s)*s; % Haar窗口高 220 C = t:t:floor(num/t)*t; % Haar窗口宽 221 NUM = 0; % Haar特征总数 222 '---- Haar特征6:上下白,中间黑(2倍宽度),(s,t)=(4,1) ---' 223 for I = 1:length(R) 224 for J = 1:length(C) 225 226 r = R(I)*delta; % Haar窗口高 227 c = C(J)*delta; % Haar窗口宽 228 nr = num-R(I)+1; % 行方向移动个数 229 nc = num-C(J)+1; % 列方向移动个数 230 231 Px0 = [0 r/4 r*3/4 r]; % 矩形坐标初始化 232 Py0 = [0 c]; 233 for i = 1:nr 234 for j = 1:nc 235 Px = Px0+(i-1)*delta; % 滑动取点 236 Py = Py0+(j-1)*delta; 237 NUM = NUM+1; 238 if show 239 plot([0 board],repmat((0:delta:board)',1,2),'k'); hold on; 240 plot(repmat((0:delta:board)',1,2),[0 board],'k'); axis tight; axis square; 241 title('Haar矩形遍历演示');xlabel('x');ylabel('y'); 242 243 plot(repmat(Px,2,1),repmat(Py',1,length(Px)),'r','LineWidth',3); 244 plot(repmat([Px(1) Px(end)]',1,2),repmat(Py,2,1),'r','LineWidth',3); hold off 245 pause(time) 246 end 247 248 end 249 end 250 251 end 252 end 253 NUM 254 %% Haar特征7:左上右下白,其它黑,(s,s)=(2,2) 255 256 s = 2; 257 t = 2; 258 R = s:s:floor(num/s)*s; % Haar窗口高 259 C = t:t:floor(num/t)*t; % Haar窗口宽 260 NUM = 0; % Haar特征总数 261 '---- Haar特征7:左上右下白,其它黑,(s,s)=(2,2) ---' 262 for I = 1:length(R) 263 for J = 1:length(C) 264 265 r = R(I)*delta; % Haar窗口高 266 c = C(J)*delta; % Haar窗口高 267 nr = num-R(I)+1; % 行方向移动个数 268 nc = num-C(J)+1; % 行方向移动个数 269 270 Px0 = [0 r/2 r]; % 矩形坐标初始化 271 Py0 = [0 c/2 c]; % 矩形坐标初始化 272 for i = 1:nr 273 for j = 1:nc 274 Px = Px0+(i-1)*delta; % 滑动取点 275 Py = Py0+(j-1)*delta; 276 NUM = NUM+1; 277 278 if show 279 plot([0 board],repmat((0:delta:board)',1,2),'k'); hold on; 280 plot(repmat((0:delta:board)',1,2),[0 board],'k'); axis tight; axis square; 281 title('Haar矩形遍历演示');xlabel('x');ylabel('y'); 282 283 plot(repmat(Px,3,1),repmat(Py',1,length(Px)),'r','LineWidth',3); 284 plot(repmat([Px(1) Px(end)]',1,3),repmat(Py,2,1),'r','LineWidth',3); hold off 285 pause(time) 286 end 287 288 end 289 end 290 291 end 292 end 293 NUM 294 %% Haar特征8:四周白,中间黑,(s,s)=(3,3) 295 s = 3; 296 t = 3; 297 R = s:s:floor(num/s)*s; % Haar窗口高 298 C = t:t:floor(num/t)*t; % Haar窗口宽 299 NUM = 0; % Haar特征总数 300 '---- Haar特征8:四周白,中间黑,(s,s)=(3,3) ---' 301 for I = 1:length(R) 302 for J = 1:length(C) 303 304 r = R(I)*delta; % Haar窗口高 305 c = C(J)*delta; % Haar窗口高 306 nr = num-R(I)+1; % 行方向移动个数 307 nc = num-C(J)+1; % 行方向移动个数 308 309 Px0 = [0 r/3 r*2/3 r]; % 矩形坐标初始化 310 Py0 = [0 c/3 c*2/3 c]; % 矩形坐标初始化 311 for i = 1:nr 312 for j = 1:nc 313 Px = Px0+(i-1)*delta; % 滑动取点 314 Py = Py0+(j-1)*delta; 315 NUM = NUM+1; 316 317 if show 318 plot([0 board],repmat((0:delta:board)',1,2),'k'); hold on; 319 plot(repmat((0:delta:board)',1,2),[0 board],'k'); axis tight; axis square; 320 title('Haar矩形遍历演示');xlabel('x');ylabel('y'); 321 322 plot(repmat(Px,4,1),repmat(Py',1,length(Px)),'r','LineWidth',3); 323 plot(repmat([Px(1) Px(end)]',1,4),repmat(Py,2,1),'r','LineWidth',3); hold off 324 pause(time) 325 end 326 327 end 328 end 329 330 end 331 end 332 NUM
运行效果部分动态图如下
那么这个特征如何表示呢?好了,这就是大牛们干的好事了。后人称这他们搞出来的这些东西叫Haar-Like特征。
Viola大牛在[1]中提出的haar特征如下: