Viola-Jones的人脸检测声称有180k的function

我一直在实施Viola-Jones的人脸检测algorithm 。 该技术依赖于在图像内放置24×24像素的子帧,随后将矩形特征放置在每个可能的大小的位置。

这些function可以由两个,三个或四个矩形组成。 下面的例子被提出。

矩形功能

他们声称详尽的集合超过了18万(第2节):

由于探测器的基本分辨率为24×24,所以矩形特征的穷尽集合相当大,超过18万。 请注意,与哈尔基不同,矩形特征集是过度完整的。

下面的陈述没有在论文中明确说明,所以他们是我的假设:

  1. 只有2个两个矩形特征,2个三个矩形特征和1个四个矩形特征。 这背后的逻辑是,我们正在观察突出显示的矩形之间的差异 ,而不是显式的颜色或亮度或任何types的东西。
  2. 我们不能将特征typesA定义为1×1像素块; 它至less必须至less有1×2像素。 此外,typesD必须至less为2×2像素,并且此规则相应地适用于其他function。
  3. 我们不能将特征typesA定义为1×3像素块,因为中间像素不能被分割,并且从其本身减去它与1×2像素块相同; 这个特征types只在偶数宽度上定义。 此外,要素typesC的宽度必须可以被3整除,并且这个规则相应地适用于其他特征。
  4. 我们无法定义宽度和/或高度为0的要素。因此,我们将xy迭代到24减去要素的大小。

基于这些假设,我已经计算了详尽的集合:

const int frameSize = 24; const int features = 5; // All five feature types: const int feature[features][2] = {{2,1}, {1,2}, {3,1}, {1,3}, {2,2}}; int count = 0; // Each feature: for (int i = 0; i < features; i++) { int sizeX = feature[i][0]; int sizeY = feature[i][1]; // Each position: for (int x = 0; x <= frameSize-sizeX; x++) { for (int y = 0; y <= frameSize-sizeY; y++) { // Each size fitting within the frameSize: for (int width = sizeX; width <= frameSize-x; width+=sizeX) { for (int height = sizeY; height <= frameSize-y; height+=sizeY) { count++; } } } } } 

结果是162,336

我发现近乎“超过180,000”的Viola&Jones所说的唯一方法是放弃假设4,并在代码中引入错误。 这包括分别改变四行:

 for (int width = 0; width < frameSize-x; width+=sizeX) for (int height = 0; height < frameSize-y; height+=sizeY) 

结果是180625 。 (注意,这将有效地防止特征触及子帧的右侧和/或底部。)

当然,现在的问题是:他们在执行过程中犯了错误吗? 考虑具有零表面的特征是否有意义? 还是我看到了错误的方式?

仔细一看,你的代码看起来对我来说是正确的。 这让人怀疑原作者是否有一个错误的错误。 我想有人应该看看OpenCV如何实现它!

尽pipe如此,让人更容易理解的一个build议是首先遍历所有大小,然后循环遍历给定大小的可能位置,从而翻转for循环的顺序:

 #include <stdio.h> int main() { int i, x, y, sizeX, sizeY, width, height, count, c; /* All five shape types */ const int features = 5; const int feature[][2] = {{2,1}, {1,2}, {3,1}, {1,3}, {2,2}}; const int frameSize = 24; count = 0; /* Each shape */ for (i = 0; i < features; i++) { sizeX = feature[i][0]; sizeY = feature[i][1]; printf("%dx%d shapes:\n", sizeX, sizeY); /* each size (multiples of basic shapes) */ for (width = sizeX; width <= frameSize; width+=sizeX) { for (height = sizeY; height <= frameSize; height+=sizeY) { printf("\tsize: %dx%d => ", width, height); c=count; /* each possible position given size */ for (x = 0; x <= frameSize-width; x++) { for (y = 0; y <= frameSize-height; y++) { count++; } } printf("count: %d\n", count-c); } } } printf("%d\n", count); return 0; } 

与之前的162336有相同的结果


为了validation它,我testing了一个4×4窗口的情况,并手动检查所有的情况(易于计数,因为1×2 / 2×1和1×3 / 3×1的形状相同,只有90度旋转):

 2x1 shapes: size: 2x1 => count: 12 size: 2x2 => count: 9 size: 2x3 => count: 6 size: 2x4 => count: 3 size: 4x1 => count: 4 size: 4x2 => count: 3 size: 4x3 => count: 2 size: 4x4 => count: 1 1x2 shapes: size: 1x2 => count: 12 +-----------------------+ size: 1x4 => count: 4 | | | | | size: 2x2 => count: 9 | | | | | size: 2x4 => count: 3 +-----+-----+-----+-----+ size: 3x2 => count: 6 | | | | | size: 3x4 => count: 2 | | | | | size: 4x2 => count: 3 +-----+-----+-----+-----+ size: 4x4 => count: 1 | | | | | 3x1 shapes: | | | | | size: 3x1 => count: 8 +-----+-----+-----+-----+ size: 3x2 => count: 6 | | | | | size: 3x3 => count: 4 | | | | | size: 3x4 => count: 2 +-----------------------+ 1x3 shapes: size: 1x3 => count: 8 Total Count = 136 size: 2x3 => count: 6 size: 3x3 => count: 4 size: 4x3 => count: 2 2x2 shapes: size: 2x2 => count: 9 size: 2x4 => count: 3 size: 4x2 => count: 3 size: 4x4 => count: 1 

所有。 中提琴和琼斯的论文还有一些混乱。

在他们的CVPR'01文件中明确指出

更具体地说,我们使用三种特征, 两个矩形特征的值是两个矩形区域内的像素总和之间的差异,这些区域具有相同的大小和形状,并且是水平的或垂直的相邻的(参见图1), 一个三矩形特征计算两个外矩形内的和,从中间矩形的和中减去最后一个四矩形特征 “。

在IJCV'04论文中,说完全一样的东西。 总共有4个特点 。 但奇怪的是,这次他们表示,详尽的function集是45396! 这似乎不是最终的版本。在这里我推测一些额外的约束,如min_width,min_height,宽高比,甚至位置。

请注意,这两篇论文都可以在他的网页上下载。

没有看完整篇文章,你的引用的措辞就伸出来了

考虑到探测器的基本分辨率是24×24,矩形特征的穷举集合相当大,超过18万。 请注意,与哈尔基不同,矩形特征集是过度完整的。

“矩形特征的集合过度完备”“穷举集”

这听起来对我来说就像一个设置,在那里我希望文章作者跟随他们如何掏空search空间到一个更有效的集合,例如,通过摆脱琐碎的情况下,如矩形零表面积。

编辑:或者使用某种机器学习algorithm,作为抽象的提示。 彻底的集合意味着所有的可能性,而不仅仅是“合理的”。

任何论文的作者都不能保证所有的假设和发现都是正确的。 如果你认为#4假设是有效的,那么保持这个假设,并试验你的理论。 你可能比原作者更成功。

相当好的观察,但他们可能会隐式地填充24×24帧,或“溢出”,并开始使用第一个像素时,如旋转转变,或布列塔尼说,他们可能会考虑一些function作为“平凡的function”然后用AdaBoost丢弃它们。

另外,我编写了代码的Python和Matlab版本,这样我就可以自己testing代码(更容易debugging和遵循),所以如果有人在某个时候发现它们,那么我将它们发布到这里。

python:

 frameSize = 24; features = 5; # All five feature types: feature = [[2,1], [1,2], [3,1], [1,3], [2,2]] count = 0; # Each feature: for i in range(features): sizeX = feature[i][0] sizeY = feature[i][1] # Each position: for x in range(frameSize-sizeX+1): for y in range(frameSize-sizeY+1): # Each size fitting within the frameSize: for width in range(sizeX,frameSize-x+1,sizeX): for height in range(sizeY,frameSize-y+1,sizeY): count=count+1 print (count) 

Matlab的:

 frameSize = 24; features = 5; % All five feature types: feature = [[2,1]; [1,2]; [3,1]; [1,3]; [2,2]]; count = 0; % Each feature: for ii = 1:features sizeX = feature(ii,1); sizeY = feature(ii,2); % Each position: for x = 0:frameSize-sizeX for y = 0:frameSize-sizeY % Each size fitting within the frameSize: for width = sizeX:sizeX:frameSize-x for height = sizeY:sizeY:frameSize-y count=count+1; end end end end end display(count) 
Interesting Posts