1

我正在开发一种简单的算法来检测几种面部表情(快乐、悲伤、愤怒......)。我是根据这篇论文来做的。我在应用 LBP 统一算子之前进行预处理,将标准化图像划分为 6x6 区域,如下例所示:

归一化图像分成 6 x 6 个区域

通过应用统一的 LBP,为每个区域提取了 59 个特征,所以最终我有 2124 个图像特征(6x6x59)。当我有大约 700 张图像来训练模型时,我认为这是太多的壮举。我读过这并不好获得良好的精度。我的问题是如何减少专长的维度或其他技术以提高算法的精度。

4

2 回答 2

1

降低特征维数并同时提高鲁棒性的一种直接方法是使用旋转不变的均匀模式R对于一个由磷像素组成的半径为圆形的邻域,LBPriu2纹理描述符通过 10 个特征来表示每个区域。因此维度从 2124 减少到 6 × 6 × 10 = 360。

于 2017-06-25T18:55:28.743 回答
0

PCA 可以帮助减少描述符的大小而不会丢失重要信息。只需谷歌“opencv pca 示例”。

另一个有用的事情是为您的统一 lbp 特征添加旋转不变性。这将提高精度并将描述符的大小从 59 显着减少到 10。

static cv::Mat rotate_table = (cv::Mat_<uchar>(1, 256) <<
                               0, 1, 1, 3, 1, 5, 3, 7, 1, 9, 5, 11, 3, 13, 7, 15, 1, 17, 9, 19, 5, 21, 11, 23,
                               3, 25, 13, 27, 7, 29, 15, 31, 1, 33, 17, 35, 9, 37, 19, 39, 5, 41, 21, 43, 11,
                               45, 23, 47, 3, 49, 25, 51, 13, 53, 27, 55, 7, 57, 29, 59, 15, 61, 31, 63, 1,
                               65, 33, 67, 17, 69, 35, 71, 9, 73, 37, 75, 19, 77, 39, 79, 5, 81, 41, 83, 21,
                               85, 43, 87, 11, 89, 45, 91, 23, 93, 47, 95, 3, 97, 49, 99, 25, 101, 51, 103,
                               13, 105, 53, 107, 27, 109, 55, 111, 7, 113, 57, 115, 29, 117, 59, 119, 15, 121,
                               61, 123, 31, 125, 63, 127, 1, 3,  65, 7, 33, 97, 67, 15, 17, 49, 69, 113, 35,
                               99, 71, 31, 9, 25, 73, 57, 37, 101, 75, 121, 19, 51, 77, 115,  39, 103, 79, 63,
                               5, 13, 81, 29, 41, 105, 83, 61, 21, 53, 85, 117, 43, 107, 87, 125, 11, 27, 89,
                               59, 45, 109, 91, 123, 23, 55, 93, 119, 47, 111, 95, 127, 3, 7, 97, 15, 49, 113,
                               99, 31, 25, 57, 101, 121, 51, 115, 103, 63, 13, 29, 105, 61, 53, 117, 107, 125,
                               27,  59, 109, 123, 55, 119, 111, 127, 7, 15, 113, 31, 57, 121, 115, 63, 29, 61,
                               117, 125, 59, 123, 119, 127, 15, 31, 121, 63, 61, 125, 123, 127, 31, 63, 125,
                               127, 63, 127, 127, 255
                               );

// the well known original uniform2 pattern
static cv::Mat uniform_table = (cv::Mat_<uchar>(1, 256) <<
                          0,1,2,3,4,58,5,6,7,58,58,58,8,58,9,10,11,58,58,58,58,58,58,58,12,58,58,58,13,58,
                          14,15,16,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,17,58,58,58,58,58,58,58,18,
                          58,58,58,19,58,20,21,22,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,
                          58,58,58,58,58,58,58,58,58,58,58,58,23,58,58,58,58,58,58,58,58,58,58,58,58,58,
                          58,58,24,58,58,58,58,58,58,58,25,58,58,58,26,58,27,28,29,30,58,31,58,58,58,32,58,
                          58,58,58,58,58,58,33,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,34,58,58,58,58,
                          58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,
                          58,35,36,37,58,38,58,58,58,39,58,58,58,58,58,58,58,40,58,58,58,58,58,58,58,58,58,
                          58,58,58,58,58,58,41,42,43,58,44,58,58,58,45,58,58,58,58,58,58,58,46,47,48,58,49,
                          58,58,58,50,51,52,58,53,54,55,56,57
                          );

static cv::Mat rotuni_table = (cv::Mat_<uchar>(1, 256) <<
                         0, 1, 1, 2, 1, 9, 2, 3, 1, 9, 9, 9, 2, 9, 3, 4, 1, 9, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9,
                         3, 9, 4, 5, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9,
                         3, 9, 9, 9, 4, 9, 5, 6, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
                         9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
                         3, 9, 9, 9, 9, 9, 9, 9, 4, 9, 9, 9, 5, 9, 6, 7, 1, 2, 9, 3, 9, 9, 9, 4, 9, 9, 9, 9,
                         9, 9, 9, 5, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 6, 9, 9, 9, 9, 9, 9, 9, 9,
                         9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7, 2, 3, 9, 4,
                         9, 9, 9, 5, 9, 9, 9, 9, 9, 9, 9, 6, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7,
                         3, 4, 9, 5, 9, 9, 9, 6, 9, 9, 9, 9, 9, 9, 9, 7, 4, 5, 9, 6, 9, 9, 9, 7, 5, 6, 9, 7,
                         6, 7, 7, 8
                         );

static void hist_patch_uniform(const Mat_<uchar> &fI, Mat &histo,
                               int histSize, bool norm, bool rotinv)
{
        cv::Mat ufI, h, n;
        if (rotinv) {
                cv::Mat r8;
                // rotation invariant transform
                cv::LUT(fI, rotate_table, r8);
                // uniformity for rotation invariant
                cv::LUT(r8, rotuni_table, ufI);
                // histSize is max 10 bins
        } else {
                cv::LUT(fI, uniform_table, ufI);
        }
        // the upper boundary is exclusive
        float range[] = {0, (float)histSize};
        const float *histRange = {range};
        cv::calcHist(&ufI, 1, 0, Mat(), h, 1, &histSize, &histRange, true, false);

        if (norm)
                normalize(h, n);
        else
                n = h;
        histo.push_back(n.reshape(1, 1));
}

输入是您的 CV_8U 灰度补丁(其中一个矩形)。输出是旋转不变的、均匀的、归一化的重塑直方图(1 行)。然后将补丁直方图连接到面部描述符中。您将拥有 6*6*10 = 360。这本身很好,但使用 pca 您可以将其设为 300 或更少,而不会丢失重要信息,甚至可以提高检测质量,因为移除了维度(假设方差小于 5%)不仅占用空间,而且主要包含噪声(例如来自传感器的高斯噪声)。

然后您可以将此 concat 直方图与人脸库或使用 svm 进行比较(rbf 内核更适合)。如果你做对了,那么预测一张脸的时间不应该超过 1-15 毫秒(我的 iphone7 上是 5 毫秒)。

希望这可以帮助。

于 2019-04-03T08:09:11.967 回答