Struck算法中通过极坐标采样方式在每个boundingbox周围得到sample框,一共得到80个sample框之后,还需要表征每一个sample框的内部特征,论文中采用了Haar-like特征。
首先在每个sample内选取4*4*2=32(a、b、c三个数组的组合)个矩形,然后计算这些矩形的Haar-like特征,因为Haar-like特征有6种,所以特征向量一共是32*6=192维,作为当前这个sample的特征向量。
1、矩形框的选取方式,这部分的matlab以及我的详细注释是这样的:
%计算sample的特征向量。在sample内选取4*4*2=32个矩形并计算这些矩形的Haar-like特征,作为sample的特征向量。
%a、b、c三个数组的组合总共有192种(4*4*2=32),所以有32个不同的矩形,但Haar-like特征有六种,所以特征向量一共是32*6=192维
function featureVector = haar_feature_vector(iH, sample)
a = [0.2 0.4 0.6 0.8];
b = [0.2 0.4 0.6 0.8]; %a、b数组是矩形的中点相对于sample的位置
c = [0.2 0.4]; %这些矩形相对于sample的大小,有0.2和0.4两种取值(即:矩形的宽为c * sample的宽,矩形的高为c * sample的高)
featureVector = zeros(1, 192);
index = 1;
% %用于画出每个矩形框,这里先画出这个sample框
% filename = 'D:\MenghanZhou\matlab_work\ICCV11_struck-matlab\ICCV11_struck-matlab\gif\rectangular_in_sample.gif';
% figure;
% axis ij
% axis([-50 160 -50 160]); % 设置坐标轴在指定的区间
% hold on;
% rectangle('Position',[sample.x,sample.y,sample.w,sample.h],'EdgeColor','r'); %画出每个矩形框
% scatter(sample.x,sample.y,'yo'); %标出每个sample框的左上角
% pause(.2);
% drawnow; %动态更新
for bi = 1 : 4
for ai = 1 : 4
for ci = 1 : 2
for type = 1 : 6 %Haar特征选取了6种特征子
abc.a = a(ai) - c(ci) / 2; %abc.a决定矩形左上角的x坐标位置
abc.b = b(bi) - c(ci) / 2; %abc.b决定矩形左上角的y坐标位置
abc.c = c(ci); %abc.c决定矩形的大小
value = haar_like_feature(iH, sample, abc, type); %记录每个矩形的6种haar特征值
featureVector(index) = value; %此时对应的特征向量的某个位置就是这个特征值
index = index + 1;
% % %得到的这些矩形框和这个sample是什么样的图形关系呢??画出来看一下
% x = sample.x + abc.a * sample.w; %矩形左上角的x坐标
% y = sample.y + abc.b * sample.h; %矩形左上角的y坐标
% w = abc.c * sample.w; %矩形的宽度
% h = abc.c * sample.h; %矩形的高度
% rectangle('Position',[x,y,w,h],'EdgeColor','r','facecolor','y'); %画出每个矩形框
% scatter(x,y,'bo'); %标出每个sample框的左上角
% pause(.2);
% drawnow; %动态更新
% %保存成gif动画
% f = getframe(gcf);
% imind = frame2im(f);
% [imind,cm] = rgb2ind(imind,256);
% if index == 2
% imwrite(imind,cm,filename,'gif', 'Loopcount',inf,'DelayTime',0.2);
% else
% imwrite(imind,cm,filename,'gif','WriteMode','append','DelayTime',0.2);
% end
end
end
end
end %会得到一个192维的特征向量,每一维都是一个sample中一个矩形的一种haar特征值
以前就提过很喜欢matlab的gif动画生成功能,这里我又用到了,来看一看这些矩形框是怎么在sample框内一一选取的吧~~感觉作者连这种奇怪的选取方式也能想出来也是充满着奇思妙想,但是,为什么要这样选取,我也不太清楚他的原因......
2、计算Haar-like特征
如何计算Haar-like特征,这里很重要一个前提就是要计算积分图像:
iH = integralImage(img); % 计算积分图像
积分图像:对于一幅灰度的图像,积分图像中的任意一点(x,y)的值是指从图像的左上角到这个点的所构成的矩形区域内所有的点的灰度值之和。
Haar特征分为四类:
边缘特征:
线性特征:
中心特征:
对角线特征:
这四类组合成特征模板。特征模板内有白色和黑色两种矩形。
论文中采用的6种特征样子,分别是:上下型、左右型、左中右型、上中下型、对角线型、中心型。见下图:
该模板的特征值=sum(白色区域灰度值之和)- sum(黑色区域灰度值之和)
所以,之前计算积分图像太重要啦~~ Haar特征值反映了图像的灰度变化情况。
高亮!!!!!
某个区域的灰度值之和=iH(该区域的右下角)-iH(该区域的左下角)-iH(该区域的右上角)+iH(该区域的左上角)
①对于上下型:
1-3-4+2=白 5-1-4+6=黑
②对于左右型:
1-3-4+2=白 6-5-1+3=黑
③对于左中右型:
6-2-5+1=白1 7-3-6+2=黑 8-7-4+3=白2
④对于上中下型:
4-2-3+1=白1 6-4-5+3=黑 8-6-7+5=白2
⑤对于对角线型:
1-4-5+3=白1 2-9-8+1=白2 9-6-1+4=黑1 8-7-1+5=黑2
⑥对于中心型:
1-3-4+2=白 8-7-6+5=黑
对应代码以及我的详细注释如下:
%输出的value代表此时这个矩形的haar特征值
function value = haar_like_feature(iH, sample, abc, type)
x = sample.x + abc.a * sample.w; %矩形左上角的x坐标
y = sample.y + abc.b * sample.h; %矩形左上角的y坐标
w = abc.c * sample.w; %矩形的宽度
h = abc.c * sample.h; %矩形的高度
switch type
case 1 %上下型
x1 = int32(round(x)); %四舍五入后转换成int32(有符号32位整数),白色和黑色填充区域左上角的x坐标都等于矩形左上角的x坐标
y1 = int32(round(y)); %白色填充区域的左上角的y坐标
y2 = int32(round(y + h / 2)); %黑色填充区域的左上角y坐标
dx = int32(floor(w)); %白色和黑色填充区域的宽度都等于矩形的宽度
dy = int32(floor(h / 2)); %白色和黑色填充区域的高度都等于矩形高度的一半
white = iH(y1 + dy, x1 + dx) + iH(y1, x1) - iH(y1, x1 + dx) - iH(y1 + dy, x1);
black = iH(y2 + dy, x1 + dx) + iH(y2, x1) - iH(y2, x1 + dx) - iH(y2 + dy, x1);
value = (white - black) / ((255.0 * 1.0 / 2) * (w * h)); %计算差值并规范化
case 2 %左右型
x1 = int32(round(x)); %白色填充区域左上角的x坐标
y1 = int32(round(y)); %白色和黑色填充区域左上角的y坐标都等于矩形左上角的y坐标
x2 = int32(round(x + w / 2)); %黑色填充区域左上角的x坐标
dx = int32(floor(w / 2)); %白色和黑色填充区域的宽度都等于矩形的宽度的一半
dy = int32(floor(h)); %白色和黑色填充区域的高度都等于矩形高度
white = iH(y1 + dy, x1 + dx) + iH(y1, x1) - iH(y1, x1 + dx) - iH(y1 + dy, x1);
black = iH(y1 + dy, x2 + dx) + iH(y1, x2) - iH(y1, x2 + dx) - iH(y1 + dy, x2);
value = (white - black) / ((255.0 * 1.0 / 2) * (w * h));
case 3 %左中右型
x1 = int32(round(x)); %白色填充区域1左上角的x坐标
y1 = int32(round(y)); %所有填充区域左上角的y坐标
x2 = int32(round(x + w / 3)); %黑色填充区域左上角的x坐标
x3 = int32(round(x + 2 * w / 3)); %白色填充区域2左上角的x坐标
dx = int32(floor(w / 3)); %所有填充区域的宽度都等于矩形的宽度的1/3
dy = int32(floor(h)); %所有填充区域的高度都等于矩形的高度
white1 = iH(y1 + dy, x1 + dx) + iH(y1, x1) - iH(y1, x1 + dx) - iH(y1 + dy, x1);
black = iH(y1 + dy, x2 + dx) + iH(y1, x2) - iH(y1, x2 + dx) - iH(y1 + dy, x2);
white2 = iH(y1 + dy, x3 + dx) + iH(y1, x3) - iH(y1, x3 + dx) - iH(y1 + dy, x3);
value = (white1 - 2*black + white2) / ((255.0 * 2.0 / 3) * (w * h));
case 4 %上中下型
x1 = int32(round(x)); %所有填充区域左上角的x坐标
y1 = int32(round(y)); %白色填充区域1左上角的y坐标
y2 = int32(round(y + h / 3)); %黑色填充区域左上角的y坐标
y3 = int32(round(y + 2 * h / 3)); %白色填充区域左上角的y坐标
dx = int32(floor(w)); %所有填充区域的宽度都等于矩形的宽度
dy = int32(floor(h / 3)); %所有填充区域的高度都等于矩形的高度的1/3
white1 = iH(y1 + dy, x1 + dx) + iH(y1, x1) - iH(y1, x1 + dx) - iH(y1 + dy, x1);
black = iH(y2 + dy, x1 + dx) + iH(y2, x1) - iH(y2, x1 + dx) - iH(y2 + dy, x1);
white2 = iH(y3 + dy, x1 + dx) + iH(y3, x1) - iH(y3, x1 + dx) - iH(y3 + dy, x1);
value = (white1 - 2*black + white2) / ((255.0 * 2.0 / 3) * (w * h));
case 5 %对角线型
x1 = int32(round(x)); %白色填充区域1左上角的x坐标
y1 = int32(round(y)); %白色填充区域1左上角的y坐标
x2 = int32(round(x + w / 2)); %白色填充区域2左上角的x坐标
y2 = int32(round(y + h / 2)); %白色填充区域2左上角的y坐标
dx = int32(floor(w / 2)); %所有填充区域的宽度都等于矩形的宽度的一半
dy = int32(floor(h / 2)); %所有填充区域的高度都等于矩形的高度的一半
white1 = iH(y1 + dy, x1 + dx) + iH(y1, x1) - iH(y1, x1 + dx) - iH(y1 + dy, x1);
white2 = iH(y2 + dy, x2 + dx) + iH(y2, x2) - iH(y2, x2 + dx) - iH(y2 + dy, x2);
black1 = iH(y2 + dy, x1 + dx) + iH(y2, x1) - iH(y2, x1 + dx) - iH(y2 + dy, x1);
black2 = iH(y1 + dy, x2 + dx) + iH(y1, x2) - iH(y1, x2 + dx) - iH(y1 + dy, x2);
value = (white1 + white2 - black1 - black2) / ((255.0 * 2.0 / 4) * (w * h));
case 6 %中心型
x1 = int32(round(x)); %白色填充区域左上角的x坐标
y1 = int32(round(y)); %白色填充区域左上角的y坐标
dx1 = int32(floor(w)); %白色填充区域的宽度都等于矩形宽度
dy1 = int32(floor(h)); %白色填充区域的高度都等于矩形高度
x2 = int32(round(x + w / 4)); %黑色填充区域的左上角x坐标
y2 = int32(round(y + h / 4)); %黑色填充区域的左上角y坐标
dx2 = int32(floor(w / 2)); %黑色填充区域的宽度都等于矩形宽度的一半
dy2 = int32(floor(h / 2)); %黑色填充区域的高度都等于矩形高度的一半
white = iH(y1 + dy1, x1 + dx1) + iH(y1, x1) - iH(y1, x1 + dx1) - iH(y1 + dy1, x1);
black = iH(y2 + dy2, x2 + dx2) + iH(y2, x2) - iH(y2, x2 + dx2) - iH(y2 + dy2, x2);
value = (white - 4 * black) / ((255 * 3.0 / 4) * (w * h));
end