Viola-Jones的脸部检测声称拥有180k功能

时间:2009-11-10 12:30:21

标签: algorithm image-processing computer-vision face-detection viola-jones

我一直在实施Viola-Jones' face detection algorithm的改编。该技术依赖于在图像中放置24x24像素的子帧,随后在每个位置放置矩形特征,并且每个位置都可以。

这些功能可以包含两个,三个或四个矩形。提供以下示例。

Rectangle features

他们声称详尽的集合超过180k(第2部分):

  

鉴于探测器的基本分辨率为24x24,矩形特征的详尽设置非常大,超过180,000。注意,与Haar基础不同,矩形集合   功能过于完整。

以下陈述未在论文中明确说明,因此它们是我的假设:

  1. 只有2个双矩形特征,2个三矩形特征和1个四矩形特征。这背后的逻辑是我们正在观察突出显示的矩形之间的差异,而不是明确的颜色或亮度或任何类型。
  2. 我们不能将要素类型A定义为1x1像素块;它必须至少至少1x2像素。此外,类型D必须至少为2x2像素,并且此规则与其他功能相对应。
  3. 我们不能将特征类型A定义为1x3像素块,因为中间像素不能被分割,并且从它自身减去它与1x2像素块相同;此要素类型仅针对偶数宽度定义。此外,要素类型C的宽度必须可以被3整除,并且此规则与其他要素相对应。
  4. 我们无法定义宽度和/或高度为0的要素。因此,我们将 x y 迭代为24减去要素的大小。
  5. 基于这些假设,我已经计算了详尽的集合:

    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&amp;琼斯说,正在放弃假设#4并在代码中引入错误。这涉及分别改变四行:

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

    结果是 180,625 。 (请注意,这将有效地防止功能接触到子帧的右侧和/或底部。)

    现在当然有一个问题:他们在实施中犯了错误吗?考虑表面为零的特征是否有意义?还是我看错了?

6 个答案:

答案 0 :(得分:38)

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

尽管如此,一个让人们更容易理解的建议是首先通过覆盖所有大小来翻转 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

的结果相同

为了验证它,我测试了4x4窗口的情况并手动检查了所有情况(易于计数,因为1x2 / 2x1和1x3 / 3x1形状相同,只有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

答案 1 :(得分:8)

所有。 Viola和Jones的论文仍然存在一些混淆。

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

  

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

在IJCV'04论文中,说的完全相同。 总共有4个功能。但奇怪的是,他们这次说明详尽的功能集是45396!这似乎不是最终版本。我猜这里引入了一些额外的约束,例如min_width,min_height,width / height ratio,甚至position。

请注意,这两篇论文都可以在his webpage上下载。

答案 2 :(得分:3)

如果没有阅读整篇论文,你的引言的措辞就会出现在我身上

  

鉴于该基本分辨率   探测器是24x24,详尽的设置   矩形特征非常大,   超过180,000。注意,不像   哈尔基础,矩形的集合   功能过于完整。

“矩形功能集过于完整” “穷举”

这对我来说听起来像是一个设置,在那里我期望论文作者跟进他们如何剔除搜索空间到一个更有效的集合的解释,例如,通过摆脱诸如表面积为零的矩形。

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

答案 3 :(得分:2)

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

答案 4 :(得分:1)

非常好的观察,但它们可能隐含地对24x24帧进行零填充,或“溢出”并在超出界限时开始使用第一个像素,如旋转移位,或者布雷顿表示他们可能会认为某些功能为“琐碎的功能“然后用AdaBoost丢弃它们。

此外,我编写了代码的Python和Matlab版本,因此我可以自己测试代码(更容易调试并跟随我),所以如果有人发现它们有用,我会在这里发布它们。

的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)

答案 5 :(得分:0)

在他们最初的2001年论文中,他们仅声明使用了三种功能:

我们使用三种功能

区域具有相同的大小和形状

由于每种类型都有两个方向,因此可以合理地假设它们总共使用6个特征(至少用于计算特征总数):2个两个矩形特征,2个三个矩形特征和2个四个矩形。矩形特征。在这种假设下,确实有超过18万个功能:

feature_types = [(1,2), (2,1), (1,3), (3,1), (2,2), (2,2)]
window_size = (24,24)

total_features = 0
for f_type in feature_types:
    for f_height in range(f_type[0], window_size[0] + 1, f_type[0]):
        for f_width in range(f_type[1], window_size[1] + 1, f_type[1]):
            total_features += (window_size[0] - f_height + 1) * (window_size[1] - f_width + 1)
            
print(total_features)
# 183072

如果删除一种四边形类型的特征(在以后的出版物中似乎是这种情况),则特征总数为162,336。

相关问题