分享

LBP特征的实现及LBP+SVM分类

 mscdj 2018-03-06

LBP这篇博客发表了有一年多的时间了,当时是为了研究生毕业论文实验而写的,后来稍微总结了一下写了这篇博客,一年多时间里,大家提了一些宝贵的修改意见,这两天将代码重构了一下,结构更加简洁清晰,速度也有所提高,非常感谢网友@LiuXueFeiNan 提出的宝贵意见,也希望大家能够提出更多更好的建议。


LBP原理

LBP的原理比较简单,网上有很多很不错的文章,这里给出几篇我认为不错的文章
目标检测的图像特征提取之(二)LBP特征

LBP local binary patterns 人脸特征提取方法

LBP特征学习及实现

如果大家想深入了解LBP,可以读一读论文
[2002 PAMI] Multiresolution gray-scale and rotation
[2006 PAMI] Face Description with Local Binary Patterns Application to Face Recognition


LBP特征向量提取的步骤

(1)计算图像中每个像素点的LBP模式(等价模式,或者旋转不变+等价模式)。
(2)然后计算每个cell的LBP特征值直方图,然后对该直方图进行归一化处理(每个cell中,对于每个bin,h[i]/=sum,sum就是一副图像中所有等价类的个数)。
(3)最后将得到的每个cell的统计直方图进行连接成为一个特征向量,也就是整幅图的LBP纹理特征向量;
然后便可利用SVM或者其他机器学习算法进行分类识别了。


LBP的实现

LBP.h

//////////////////////////////////////////////////////////////////////////
//  LBP.h (2.0)
// 2015-6-30,by QQ
//
// Please contact me if you find any bugs, or have any suggestions.
// Contact:
//      Telephone:15366105857
//      Email:654393155@qq.com
//      Blog: http://blog.csdn.net/qianqing13579
//////////////////////////////////////////////////////////////////////////
// updated 2016-12-12 01:12:55 by QQ, LBP 1.1,GetMinBinary()函数修改为查找表,提高了计算速度
// updated 2016-12-13 14:41:58 by QQ, LBP 2.0,先计算整幅图像的LBP特征图,然后计算每个cell的LBP直方图

#ifndef __LBP_H__
#define __LBP_H__
#include "opencv2/opencv.hpp"
#include<vector>
using namespace std;
using namespace cv;

class LBP
{
public:

    // 计算基本的256维LBP特征向量
    void ComputeLBPFeatureVector_256(const Mat &srcImage, Size cellSize,Mat &featureVector);
    void ComputeLBPImage_256(const Mat &srcImage, Mat &LBPImage);// 计算256维LBP特征图

    // 计算灰度不变+等价模式LBP特征向量(58种模式)
    void ComputeLBPFeatureVector_Uniform(const Mat &srcImage, Size cellSize, Mat &featureVector);
    void ComputeLBPImage_Uniform(const Mat &srcImage, Mat &LBPImage);// 计算等价模式LBP特征图

    // 计算灰度不变+旋转不变+等价模式LBP特征向量(9种模式)
    void ComputeLBPFeatureVector_Rotation_Uniform(const Mat &srcImage, Size cellSize, Mat &featureVector);
    void ComputeLBPImage_Rotation_Uniform(const Mat &srcImage, Mat &LBPImage); // 计算灰度不变+旋转不变+等价模式LBP特征图,使用查找表

    // Test
    void Test();// 测试灰度不变+旋转不变+等价模式LBP
    void TestGetMinBinaryLUT();

private:
    void BuildUniformPatternTable(int *table); // 计算等价模式查找表
    int GetHopCount(int i);// 获取i中0,1的跳变次数

    void ComputeLBPImage_Rotation_Uniform_2(const Mat &srcImage, Mat &LBPImage);// 计算灰度不变+旋转不变+等价模式LBP特征图,不使用查找表
    int ComputeValue9(int value58);// 计算9种等价模式
    int GetMinBinary(int binary);// 通过LUT计算最小二进制
    uchar GetMinBinary(uchar *binary); // 计算得到最小二进制

};

#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

LBP.cpp

#include"LBP.h"

//获取i中0,1的跳变次数
int LBP::GetHopCount(int i)
{
    // 转换为二进制
    int a[8] = { 0 };
    int k = 7;
    while (i)
    {
        // 除2取余
        a[k] = i % 2;
        i/=2;
        --k;
    }

    // 计算跳变次数
    int count = 0;
    for (int k = 0; k<8; ++k)
    {
        // 注意,是循环二进制,所以需要判断是否为8
        if (a[k] != a[k + 1 == 8 ? 0 : k + 1])
        {
            ++count;
        }
    }
    return count;

}

// 建立等价模式表
// 这里为了便于建立LBP特征图,58种等价模式序号从1开始:1~58,第59类混合模式映射为0
void LBP::BuildUniformPatternTable(int *table)
{
    memset(table, 0, 256*sizeof(int));
    uchar temp = 1;
    for (int i = 0; i<256; ++i)
    {
        if (GetHopCount(i) <= 2)
        {
            table[i] = temp;
            temp++;
        }
    }

}

void LBP::ComputeLBPFeatureVector_256(const Mat &srcImage, Size cellSize, Mat &featureVector)
{
    // 参数检查,内存分配
    CV_Assert(srcImage.depth() == CV_8U&&srcImage.channels() == 1);

    Mat LBPImage;
    ComputeLBPImage_256(srcImage,LBPImage);

    // 计算cell个数
    int widthOfCell = cellSize.width;
    int heightOfCell = cellSize.height;
    int numberOfCell_X = srcImage.cols / widthOfCell;// X方向cell的个数
    int numberOfCell_Y = srcImage.rows / heightOfCell;

    // 特征向量的个数
    int numberOfDimension = 256 * numberOfCell_X*numberOfCell_Y;
    featureVector.create(1, numberOfDimension, CV_32FC1);
    featureVector.setTo(Scalar(0));

    // 计算LBP特征向量
    int stepOfCell=srcImage.cols;
    int pixelCount = cellSize.width*cellSize.height;
    float *dataOfFeatureVector=(float *)featureVector.data;

    // cell的特征向量在最终特征向量中的起始位置
    int index = -256;
    for (int y = 0; y <= numberOfCell_Y - 1; ++y)
    {
        for (int x = 0; x <= numberOfCell_X - 1; ++x)
        {
            index+=256;

            // 计算每个cell的LBP直方图
            Mat cell = LBPImage(Rect(x * widthOfCell, y * heightOfCell, widthOfCell, heightOfCell));
            uchar *rowOfCell=cell.data;
            for(int y_Cell=0;y_Cell<=cell.rows-1;++y_Cell,rowOfCell+=stepOfCell)
            {
                uchar *colOfCell=rowOfCell;
                for(int x_Cell=0;x_Cell<=cell.cols-1;++x_Cell,++colOfCell)
                {
                    ++dataOfFeatureVector[index + colOfCell[0]];
                }
            }

            // 一定要归一化!否则分类器计算误差很大
            for (int i = 0; i <= 255; ++i)
                dataOfFeatureVector[index + i] /= pixelCount;

        }
    }

}

//srcImage:灰度图
//LBPImage:LBP图
void LBP::ComputeLBPImage_256(const Mat &srcImage, Mat &LBPImage)
{
    // 参数检查,内存分配
    CV_Assert(srcImage.depth() == CV_8U&&srcImage.channels() == 1);
    LBPImage.create(srcImage.size(), srcImage.type());

    // 扩充原图像边界,便于边界处理
    Mat extendedImage;
    copyMakeBorder(srcImage, extendedImage, 1, 1, 1, 1, BORDER_DEFAULT);

    // 计算LBP特征图
    int heightOfExtendedImage = extendedImage.rows;
    int widthOfExtendedImage = extendedImage.cols;
    int widthOfLBP=LBPImage.cols;
    uchar *rowOfExtendedImage= extendedImage.data+widthOfExtendedImage+1;
    uchar *rowOfLBPImage = LBPImage.data;
    for (int y = 1; y <= heightOfExtendedImage - 2; ++y, rowOfExtendedImage += widthOfExtendedImage, rowOfLBPImage += widthOfLBP)
    {
        // 列
        uchar *colOfExtendedImage = rowOfExtendedImage;
        uchar *colOfLBPImage = rowOfLBPImage;
        for (int x = 1; x <= widthOfExtendedImage - 2; ++x,++colOfExtendedImage,++colOfLBPImage)
        {
            // 计算LBP值
            int LBPValue = 0;
            if (colOfExtendedImage[0 - widthOfExtendedImage - 1] >= colOfExtendedImage[0])
                LBPValue += 128;
            if (colOfExtendedImage[0 - widthOfExtendedImage ] >= colOfExtendedImage[0])
                LBPValue += 64;
            if (colOfExtendedImage[0 - widthOfExtendedImage +1] >= colOfExtendedImage[0])
                LBPValue += 32;
            if (colOfExtendedImage[0 +1] >= colOfExtendedImage[0])
                LBPValue += 16;
            if (colOfExtendedImage[0 + widthOfExtendedImage + 1] >= colOfExtendedImage[0])
                LBPValue += 8;
            if (colOfExtendedImage[0 + widthOfExtendedImage] >= colOfExtendedImage[0])
                LBPValue += 4;
            if (colOfExtendedImage[0 + widthOfExtendedImage - 1] >= colOfExtendedImage[0])
                LBPValue += 2;
            if (colOfExtendedImage[0 - 1] >= colOfExtendedImage[0])
                LBPValue += 1;

            colOfLBPImage[0] = LBPValue;

        }  // x

    }// y


}

// cellSize:每个cell的大小,如16*16
void LBP::ComputeLBPFeatureVector_Uniform(const Mat &srcImage, Size cellSize, Mat &featureVector)
{
    // 参数检查,内存分配
    CV_Assert(srcImage.depth() == CV_8U&&srcImage.channels() == 1);

    Mat LBPImage;
    ComputeLBPImage_Uniform(srcImage,LBPImage);

    // 计算cell个数
    int widthOfCell = cellSize.width;
    int heightOfCell = cellSize.height;
    int numberOfCell_X = srcImage.cols / widthOfCell;// X方向cell的个数
    int numberOfCell_Y = srcImage.rows / heightOfCell;

    // 特征向量的个数
    int numberOfDimension = 58 * numberOfCell_X*numberOfCell_Y;
    featureVector.create(1, numberOfDimension, CV_32FC1);
    featureVector.setTo(Scalar(0));

    // 计算LBP特征向量
    int stepOfCell=srcImage.cols;
    int index = -58;// cell的特征向量在最终特征向量中的起始位置
    float *dataOfFeatureVector=(float *)featureVector.data;
    for (int y = 0; y <= numberOfCell_Y - 1; ++y)
    {
        for (int x = 0; x <= numberOfCell_X - 1; ++x)
        {
            index+=58;

            // 计算每个cell的LBP直方图
            Mat cell = LBPImage(Rect(x * widthOfCell, y * heightOfCell, widthOfCell, heightOfCell));
            uchar *rowOfCell=cell.data;
            int sum = 0; // 每个cell的等价模式总数
            for(int y_Cell=0;y_Cell<=cell.rows-1;++y_Cell,rowOfCell+=stepOfCell)
            {
                uchar *colOfCell=rowOfCell;
                for(int x_Cell=0;x_Cell<=cell.cols-1;++x_Cell,++colOfCell)
                {
                    if(colOfCell[0]!=0)
                    {
                        // 在直方图中转化为0~57,所以是colOfCell[0] - 1
                        ++dataOfFeatureVector[index + colOfCell[0]-1];
                        ++sum;
                    }
                }
            }

            // 一定要归一化!否则分类器计算误差很大
            for (int i = 0; i <= 57; ++i)
                dataOfFeatureVector[index + i] /= sum;

        }
    }
}

// 计算等价模式LBP特征图,为了方便表示特征图,58种等价模式表示为1~58,第59种混合模式表示为0
// 注:你可以将第59类混合模式映射为任意数值,因为要突出等价模式特征,所以非等价模式设置为0比较好
void LBP::ComputeLBPImage_Uniform(const Mat &srcImage, Mat &LBPImage)
{
    // 参数检查,内存分配
    CV_Assert(srcImage.depth() == CV_8U&&srcImage.channels() == 1);
    LBPImage.create(srcImage.size(), srcImage.type());

    // 计算LBP图
    // 扩充原图像边界,便于边界处理
    Mat extendedImage;
    copyMakeBorder(srcImage, extendedImage, 1, 1, 1, 1, BORDER_DEFAULT);

    // 构建LBP 等价模式查找表
    //int table[256];
    //BuildUniformPatternTable(table);

    // LUT(256种每一种模式对应的等价模式)
    static const int table[256] = { 1, 2, 3, 4, 5, 0, 6, 7, 8, 0, 0, 0, 9, 0, 10, 11, 12, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 14, 0, 15, 16, 17, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25,
        0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 27, 0, 28, 29, 30, 31, 0, 32, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0
        , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 36, 37, 38, 0, 39, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42
        , 43, 44, 0, 45, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 47, 48, 49, 0, 50, 0, 0, 0, 51, 52, 53, 0, 54, 55, 56, 57, 58 };

    // 计算LBP
    int heightOfExtendedImage = extendedImage.rows;
    int widthOfExtendedImage = extendedImage.cols;
    int widthOfLBP=LBPImage.cols;
    uchar *rowOfExtendedImage = extendedImage.data+widthOfExtendedImage+1;
    uchar *rowOfLBPImage = LBPImage.data;
    for (int y = 1; y <= heightOfExtendedImage - 2; ++y,rowOfExtendedImage += widthOfExtendedImage, rowOfLBPImage += widthOfLBP)
    {
        // 列
        uchar *colOfExtendedImage = rowOfExtendedImage;
        uchar *colOfLBPImage = rowOfLBPImage;
        for (int x = 1; x <= widthOfExtendedImage - 2; ++x, ++colOfExtendedImage, ++colOfLBPImage)
        {
            // 计算LBP值
            int LBPValue = 0;
            if (colOfExtendedImage[0 - widthOfExtendedImage - 1] >= colOfExtendedImage[0])
                LBPValue += 128;
            if (colOfExtendedImage[0 - widthOfExtendedImage] >= colOfExtendedImage[0])
                LBPValue += 64;
            if (colOfExtendedImage[0 - widthOfExtendedImage + 1] >= colOfExtendedImage[0])
                LBPValue += 32;
            if (colOfExtendedImage[0 + 1] >= colOfExtendedImage[0])
                LBPValue += 16;
            if (colOfExtendedImage[0 + widthOfExtendedImage + 1] >= colOfExtendedImage[0])
                LBPValue += 8;
            if (colOfExtendedImage[0 + widthOfExtendedImage] >= colOfExtendedImage[0])
                LBPValue += 4;
            if (colOfExtendedImage[0 + widthOfExtendedImage - 1] >= colOfExtendedImage[0])
                LBPValue += 2;
            if (colOfExtendedImage[0 - 1] >= colOfExtendedImage[0])
                LBPValue += 1;

            colOfLBPImage[0] = table[LBPValue];

        } // x

    }// y
}

// 计算9种等价模式,等价模式编号也是从1开始:1~9
int LBP::ComputeValue9(int value58)
{
    int value9 = 0;
    switch (value58)
    {
    case 1: 
        value9 = 1;
        break;
    case 2:
        value9 = 2;
        break;
    case 4:
        value9 = 3;
        break;
    case 7:
        value9 = 4;
        break;
    case 11:
        value9 = 5;
        break;
    case 16:
        value9 = 6;
        break;
    case 22:
        value9 = 7;
        break;
    case 29:
        value9 = 8;
        break;
    case 58:
        value9 = 9;
        break;
    }

    return value9;

}

int LBP::GetMinBinary(int binary)
{
    static const int miniBinaryLUT[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, 9, 17, 25, 9, 37, 19, 39, 5, 37, 21, 43, 11, 45,
        23, 47, 3, 19, 25, 51, 13, 53, 27, 55, 7, 39, 29, 59, 15, 61, 31, 63, 1, 5, 9, 13, 17, 21, 25,
        29, 9, 37, 37, 45, 19, 53, 39, 61, 5, 21, 37, 53, 21, 85, 43, 87, 11, 43, 45, 91, 23, 87, 47, 95,
        3, 11, 19, 27, 25, 43, 51, 59, 13, 45, 53, 91, 27, 91, 55, 111, 7, 23, 39, 55, 29, 87, 59, 119, 15,
        47, 61, 111, 31, 95, 63, 127, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 9, 25, 37,
        39, 37, 43, 45, 47, 19, 51, 53, 55, 39, 59, 61, 63, 5, 13, 21, 29, 37, 45, 53, 61, 21, 53, 85,
        87, 43, 91, 87, 95, 11, 27, 43, 59, 45, 91, 91, 111, 23, 55, 87, 119, 47, 111, 95, 127, 3,
        7, 11, 15, 19, 23, 27, 31, 25, 39, 43, 47, 51, 55, 59, 63, 13, 29, 45, 61, 53, 87, 91, 95, 27, 59,
        91, 111, 55, 119, 111, 127, 7, 15, 23, 31, 39, 47, 55, 63, 29, 61, 87, 95, 59, 111, 119, 127, 15, 31, 47, 63,
        61, 95, 111, 127, 31, 63, 95, 127, 63, 127, 127, 255};

    return miniBinaryLUT[binary];
}

// 获取循环二进制的最小二进制模式
uchar LBP::GetMinBinary(uchar *binary)
{
    // 计算8个二进制
    uchar LBPValue[8] = { 0 };
    for (int i = 0; i <= 7; ++i)
    {
        LBPValue[0] += binary[i] <<(7-i);
        LBPValue[1] += binary[(i+7)%8] << (7 - i);
        LBPValue[2] += binary[(i + 6) % 8] << (7 - i);
        LBPValue[3] += binary[(i + 5) % 8] << (7 - i);
        LBPValue[4] += binary[(i + 4) % 8] << (7 - i);
        LBPValue[5] += binary[(i + 3) % 8] << (7 - i);
        LBPValue[6] += binary[(i + 2) % 8] << (7 - i);
        LBPValue[7] += binary[(i + 1) % 8] << (7 - i);
    }

    // 选择最小的
    uchar minValue = LBPValue[0];
    for (int i = 1; i <= 7; ++i)
    {
        if (LBPValue[i] < minValue)
        {
            minValue = LBPValue[i];
        }
    }

    return minValue;

}
// cellSize:每个cell的大小,如16*16
void LBP::ComputeLBPFeatureVector_Rotation_Uniform(const Mat &srcImage, Size cellSize, Mat &featureVector)
{
    // 参数检查,内存分配
    CV_Assert(srcImage.depth() == CV_8U&&srcImage.channels() == 1);

    Mat LBPImage;
    ComputeLBPImage_Rotation_Uniform(srcImage,LBPImage);

    // 计算cell个数
    int widthOfCell = cellSize.width;
    int heightOfCell = cellSize.height;
    int numberOfCell_X = srcImage.cols / widthOfCell;// X方向cell的个数
    int numberOfCell_Y = srcImage.rows / heightOfCell;

    // 特征向量的个数
    int numberOfDimension = 9 * numberOfCell_X*numberOfCell_Y;
    featureVector.create(1, numberOfDimension, CV_32FC1);
    featureVector.setTo(Scalar(0));

    // 计算LBP特征向量
    int stepOfCell=srcImage.cols;
    int index = -9;// cell的特征向量在最终特征向量中的起始位置
    float *dataOfFeatureVector=(float *)featureVector.data;
    for (int y = 0; y <= numberOfCell_Y - 1; ++y)
    {
        for (int x = 0; x <= numberOfCell_X - 1; ++x)
        {
            index+=9;

            // 计算每个cell的LBP直方图
            Mat cell = LBPImage(Rect(x * widthOfCell, y * heightOfCell, widthOfCell, heightOfCell));
            uchar *rowOfCell=cell.data;
            int sum = 0; // 每个cell的等价模式总数
            for(int y_Cell=0;y_Cell<=cell.rows-1;++y_Cell,rowOfCell+=stepOfCell)
            {
                uchar *colOfCell=rowOfCell;
                for(int x_Cell=0;x_Cell<=cell.cols-1;++x_Cell,++colOfCell)
                {
                    if(colOfCell[0]!=0)
                    {
                         // 在直方图中转化为0~8,所以是colOfCell[0] - 1
                        ++dataOfFeatureVector[index + colOfCell[0]-1];
                        ++sum;
                    }
                }
            }

            // 直方图归一化
            for (int i = 0; i <= 8; ++i)
                dataOfFeatureVector[index + i] /= sum;

        }
    }
}

void LBP::ComputeLBPImage_Rotation_Uniform(const Mat &srcImage, Mat &LBPImage)
{
    // 参数检查,内存分配
    CV_Assert(srcImage.depth() == CV_8U&&srcImage.channels() == 1);
    LBPImage.create(srcImage.size(), srcImage.type());

    // 扩充图像,处理边界情况
    Mat extendedImage;
    copyMakeBorder(srcImage, extendedImage, 1, 1, 1, 1, BORDER_DEFAULT);

    // 构建LBP 等价模式查找表
    //int table[256];
    //BuildUniformPatternTable(table);

    // 查找表
    static const int table[256] = { 1, 2, 3, 4, 5, 0, 6, 7, 8, 0, 0, 0, 9, 0, 10, 11, 12, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 14, 0, 15, 16, 17, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25,
        0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 27, 0, 28, 29, 30, 31, 0, 32, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0
        , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 36, 37, 38, 0, 39, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42
        , 43, 44, 0, 45, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 47, 48, 49, 0, 50, 0, 0, 0, 51, 52, 53, 0, 54, 55, 56, 57, 58 };

    int heigthOfExtendedImage = extendedImage.rows;
    int widthOfExtendedImage = extendedImage.cols;
    int widthOfLBPImage = LBPImage.cols;

    uchar *rowOfExtendedImage = extendedImage.data + widthOfExtendedImage + 1;
    uchar *rowOfLBPImage = LBPImage.data;
    for (int y = 1; y <= heigthOfExtendedImage - 2; ++y, rowOfExtendedImage += widthOfExtendedImage, rowOfLBPImage += widthOfLBPImage)
    {
        // 列
        uchar *colOfExtendedImage = rowOfExtendedImage;
        uchar *colOfLBPImage = rowOfLBPImage;
        for (int x = 1; x <= widthOfExtendedImage - 2; ++x, ++colOfExtendedImage, ++colOfLBPImage)
        {
            // 计算LBP值
            int LBPValue = 0;
            if (colOfExtendedImage[0 - widthOfExtendedImage - 1] >= colOfExtendedImage[0])
                LBPValue += 128;
            if (colOfExtendedImage[0 - widthOfExtendedImage] >= colOfExtendedImage[0])
                LBPValue += 64;
            if (colOfExtendedImage[0 - widthOfExtendedImage + 1] >= colOfExtendedImage[0])
                LBPValue += 32;
            if (colOfExtendedImage[0 + 1] >= colOfExtendedImage[0])
                LBPValue += 16;
            if (colOfExtendedImage[0 + widthOfExtendedImage + 1] >= colOfExtendedImage[0])
                LBPValue += 8;
            if (colOfExtendedImage[0 + widthOfExtendedImage] >= colOfExtendedImage[0])
                LBPValue += 4;
            if (colOfExtendedImage[0 + widthOfExtendedImage - 1] >= colOfExtendedImage[0])
                LBPValue += 2;
            if (colOfExtendedImage[0 - 1] >= colOfExtendedImage[0])
                LBPValue += 1;

            int minValue = GetMinBinary(LBPValue);

            // 计算58种等价模式LBP
            int value58 = table[minValue];

            // 计算9种等价模式
            colOfLBPImage[0] = ComputeValue9(value58);
        }

    }

}

void LBP::ComputeLBPImage_Rotation_Uniform_2(const Mat &srcImage, Mat &LBPImage)
{
    // 参数检查,内存分配
    CV_Assert(srcImage.depth() == CV_8U&&srcImage.channels() == 1);
    LBPImage.create(srcImage.size(), srcImage.type());

    // 扩充图像,处理边界情况
    Mat extendedImage;
    copyMakeBorder(srcImage, extendedImage, 1, 1, 1, 1, BORDER_DEFAULT);

    // 构建LBP 等价模式查找表
    //int table[256];
    //BuildUniformPatternTable(table);

    // 通过查找表
    static const int table[256] = { 1, 2, 3, 4, 5, 0, 6, 7, 8, 0, 0, 0, 9, 0, 10, 11, 12, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 14, 0, 15, 16, 17, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25,
        0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 27, 0, 28, 29, 30, 31, 0, 32, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0
        , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 36, 37, 38, 0, 39, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42
        , 43, 44, 0, 45, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 47, 48, 49, 0, 50, 0, 0, 0, 51, 52, 53, 0, 54, 55, 56, 57, 58 };

    uchar binary[8] = { 0 };// 记录每个像素的LBP值
    int heigthOfExtendedImage = extendedImage.rows;
    int widthOfExtendedImage = extendedImage.cols;
    int widthOfLBPImage = LBPImage.cols;

    uchar *rowOfExtendedImage = extendedImage.data + widthOfExtendedImage + 1;
    uchar *rowOfLBPImage = LBPImage.data;
    for (int y = 1; y <= heigthOfExtendedImage - 2; ++y, rowOfExtendedImage += widthOfExtendedImage, rowOfLBPImage += widthOfLBPImage)
    {
        // 列
        uchar *colOfExtendedImage = rowOfExtendedImage;
        uchar *colOfLBPImage = rowOfLBPImage;
        for (int x = 1; x <= widthOfExtendedImage - 2; ++x, ++colOfExtendedImage, ++colOfLBPImage)
        {
            // 计算旋转不变LBP(最小的二进制模式)
            binary[0] = colOfExtendedImage[0 - widthOfExtendedImage - 1] >= colOfExtendedImage[0] ? 1 : 0;
            binary[1] = colOfExtendedImage[0 - widthOfExtendedImage] >= colOfExtendedImage[0] ? 1 : 0;
            binary[2] = colOfExtendedImage[0 - widthOfExtendedImage + 1] >= colOfExtendedImage[0] ? 1 : 0;
            binary[3] = colOfExtendedImage[0 + 1] >= colOfExtendedImage[0] ? 1 : 0;
            binary[4] = colOfExtendedImage[0 + widthOfExtendedImage + 1] >= colOfExtendedImage[0] ? 1 : 0;
            binary[5] = colOfExtendedImage[0 + widthOfExtendedImage] >= colOfExtendedImage[0] ? 1 : 0;
            binary[6] = colOfExtendedImage[0 + widthOfExtendedImage - 1] >= colOfExtendedImage[0] ? 1 : 0;
            binary[7] = colOfExtendedImage[0 - 1] >= colOfExtendedImage[0] ? 1 : 0;

            int minValue = GetMinBinary(binary);

            // 计算58种等价模式LBP
            int value58=table[minValue];

            // 计算9种等价模式
            colOfLBPImage[0] = ComputeValue9(value58);
        }

    }
}


// 验证灰度不变+旋转不变+等价模式种类
void LBP::Test()
{
    uchar LBPValue[8] = { 0 };
    int k = 7, j;
    int temp;
    LBP lbp;
    int number[256] = { 0 };
    int numberOfMinBinary = 0;

    // 旋转不变
    for (int i = 0; i < 256; ++i)
    {
        k = 7;
        temp = i;
        while (k >= 0)
        {
            LBPValue[k] = temp & 1;
            temp = temp >> 1;
            --k;
        }
        int minBinary = lbp.GetMinBinary(LBPValue);

        // 查找有无重复的
        for (j = 0; j <= numberOfMinBinary - 1; ++j)
        {
            if (number[j] == minBinary)
                break;
        }
        if (j == numberOfMinBinary)
        {
            number[numberOfMinBinary++] = minBinary;
        }
    }
    cout << "旋转不变一共有:"<<numberOfMinBinary <<"种"<< endl;

    // LUT
    static const int table[256] = { 1, 2, 3, 4, 5, 0, 6, 7, 8, 0, 0, 0, 9, 0, 10, 11, 12, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 14, 0, 15, 16, 17, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25,
        0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 27, 0, 28, 29, 30, 31, 0, 32, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0
        , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 36, 37, 38, 0, 39, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42
        , 43, 44, 0, 45, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 47, 48, 49, 0, 50, 0, 0, 0, 51, 52, 53, 0, 54, 55, 56, 57, 58 };

    for (int i = 0; i <= numberOfMinBinary - 1; ++i)
    {
        cout << "旋转不变的LBP:"<<number[i] << " "<<"对应的等价模式:" << table[number[i]] << endl;
    }

}

void LBP::TestGetMinBinaryLUT()
{
    for (int i = 0; i <= 255; ++i)
    {
        uchar a[8] = { 0 };
        int k = 7;
        int j = i;
        while (j)
        {
            // 除2取余
            a[k] = j % 2;
            j /= 2;
            --k;
        }
        uchar minBinary=GetMinBinary(a);
        printf("%d,",minBinary);

    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508
  • 509
  • 510
  • 511
  • 512
  • 513
  • 514
  • 515
  • 516
  • 517
  • 518
  • 519
  • 520
  • 521
  • 522
  • 523
  • 524
  • 525
  • 526
  • 527
  • 528
  • 529
  • 530
  • 531
  • 532
  • 533
  • 534
  • 535
  • 536
  • 537
  • 538
  • 539
  • 540
  • 541
  • 542
  • 543
  • 544
  • 545
  • 546
  • 547
  • 548
  • 549
  • 550
  • 551
  • 552
  • 553
  • 554
  • 555
  • 556
  • 557
  • 558
  • 559
  • 560
  • 561
  • 562
  • 563
  • 564
  • 565
  • 566
  • 567
  • 568
  • 569
  • 570
  • 571
  • 572
  • 573
  • 574
  • 575
  • 576
  • 577
  • 578
  • 579
  • 580
  • 581
  • 582
  • 583
  • 584
  • 585
  • 586
  • 587
  • 588
  • 589
  • 590
  • 591
  • 592
  • 593
  • 594
  • 595
  • 596
  • 597
  • 598
  • 599
  • 600
  • 601
  • 602
  • 603
  • 604
  • 605
  • 606
  • 607
  • 608
  • 609
  • 610
  • 611
  • 612
  • 613
  • 614
  • 615
  • 616
  • 617

SVM测试程序

SVMTest.h

//////////////////////////////////////////////////////////////////////////
//  SVMTest.h
// 2016-12-12,by QQ
//
// Please contact me if you find any bugs, or have any suggestions.
// Contact:
//      Telephone:15366105857
//      Email:654393155@qq.com
//      Blog: http://blog.csdn.net/qianqing13579
//////////////////////////////////////////////////////////////////////////

#ifndef __SVMTEST__
#define __SVMTEST__

#include "opencv2/ml.hpp"
//#include"../Utility/CommonUtility.h"
//#include"../Utility/LogInterface.h"
#include<fstream>
#include"LBP.h"
using namespace cv::ml;

// if you do not need log,comment it,just like :#define LOG_WARN_SVM_TEST(...)                  //LOG4CPLUS_MACRO_FMT_BODY ("SVMTest", WARN_LOG_LEVEL, __VA_ARGS__)
#define LOG_DEBUG_SVM_TEST(...)                //LOG4CPLUS_MACRO_FMT_BODY ("SVMTest", DEBUG_LOG_LEVEL, __VA_ARGS__)
#define LOG_ERROR_SVM_TEST(...)                 //LOG4CPLUS_MACRO_FMT_BODY ("SVMTest", ERROR_LOG_LEVEL, __VA_ARGS__)
#define LOG_INFO_SVM_TEST(...)                    //LOG4CPLUS_MACRO_FMT_BODY ("SVMTest", INFO_LOG_LEVEL, __VA_ARGS__)
#define LOG_WARN_SVM_TEST(...)                  //LOG4CPLUS_MACRO_FMT_BODY ("SVMTest", WARN_LOG_LEVEL, __VA_ARGS__)
//#define CONFIG_FILE                                              "./Resource/Configuration.xml"
#define CELL_SIZE   16

class SVMTest
{
public:
    SVMTest(const string &_trainDataFileList,
              const string &_testDataFileList,
              const string &_svmModelFilePath,
              const string &_predictResultFilePath,
              SVM::Types svmType, // See SVM::Types. Default value is SVM::C_SVC.
              SVM::KernelTypes kernel,
              double c, // For SVM::C_SVC, SVM::EPS_SVR or SVM::NU_SVR. Default value is 0.
              double coef,  // For SVM::POLY or SVM::SIGMOID. Default value is 0.
              double degree, // For SVM::POLY. Default value is 0.
              double gamma, // For SVM::POLY, SVM::RBF, SVM::SIGMOID or SVM::CHI2. Default value is 1.
              double nu,  // For SVM::NU_SVC, SVM::ONE_CLASS or SVM::NU_SVR. Default value is 0.
              double p // For SVM::EPS_SVR. Default value is 0.
              );
    bool Initialize();
    virtual ~SVMTest();

    void Train();
    void Predict();

private:
    string trainDataFileList;
    string testDataFileList;
    string svmModelFilePath;
    string predictResultFilePath;

    // SVM
    Ptr<SVM> svm;

    // feature extracting(HOG,LBP,Haar,etc)
    LBP lbp;


};


#endif // SVMTEST
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

SVMTest.cpp

#include"SVMTest.h"

SVMTest::SVMTest(const string &_trainDataFileList,
                     const string &_testDataFileList,
                     const string &_svmModelFilePath,
                     const string &_predictResultFilePath,
                     SVM::Types svmType, // See SVM::Types. Default value is SVM::C_SVC.
                     SVM::KernelTypes kernel,
                     double c, // For SVM::C_SVC, SVM::EPS_SVR or SVM::NU_SVR. Default value is 0.
                     double coef,  // For SVM::POLY or SVM::SIGMOID. Default value is 0.
                     double degree, // For SVM::POLY. Default value is 0.
                     double gamma, // For SVM::POLY, SVM::RBF, SVM::SIGMOID or SVM::CHI2. Default value is 1.
                     double nu,  // For SVM::NU_SVC, SVM::ONE_CLASS or SVM::NU_SVR. Default value is 0.
                     double p // For SVM::EPS_SVR. Default value is 0.
                     ):
                       trainDataFileList(_trainDataFileList),
                       testDataFileList(_testDataFileList),
                       svmModelFilePath(_svmModelFilePath),
                       predictResultFilePath(_predictResultFilePath)
{
    // set svm param
    svm = SVM::create();
    svm->setC(c);
    svm->setCoef0(coef);
    svm->setDegree(degree);
    svm->setGamma(gamma);
    svm->setKernel(kernel);
    svm->setNu(nu);
    svm->setP(p);
    svm->setType(svmType);

    //svm->setTermCriteria(TermCriteria(TermCriteria::EPS, 1000, FLT_EPSILON)); // based on accuracy
    svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6)); // based on the maximum number of iterations
}

bool SVMTest::Initialize()
{
    // initialize log
    //InitializeLog("SVMTest");

   return true;

}

SVMTest::~SVMTest()
{
}

void SVMTest::Train()
{
    // 读入训练样本图片路径和类别
   std::vector<string> imagePaths;
   std::vector<int> imageClasses;
   string line;
   std::ifstream trainingData(trainDataFileList,ios::out);
   while (getline(trainingData, line))
   {
       if(line.empty())
           continue;

       stringstream stream(line);
       string imagePath,imageClass;
       stream>>imagePath;
       stream>>imageClass;

       imagePaths.push_back(imagePath);
       imageClasses.push_back(atoi(imageClass.c_str()));
   }
   trainingData.close();

   printf("%d\n",imagePaths.size());

    // extract feature
   Mat featureVectorsOfSample;
   Mat classOfSample;
   printf("get feature...\n");
   LOG_INFO_SVM_TEST("get feature...");
   for(int i=0;i<=imagePaths.size()-1;++i)
   {
       Mat srcImage=imread(imagePaths[i],-1);
       if(srcImage.empty()||srcImage.depth()!=CV_8U)
       {
           printf("%s srcImage.empty()||srcImage.depth()!=CV_8U!\n",imagePaths[i].c_str());
           LOG_ERROR_SVM_TEST("%s srcImage.empty()||srcImage.depth()!=CV_8U!",imagePaths[i].c_str());
           continue;
       }

       // extract feature
       Mat featureVector;
       lbp.ComputeLBPFeatureVector_Rotation_Uniform(srcImage,Size(CELL_SIZE,CELL_SIZE),featureVector);
       if(featureVector.empty())
           continue;

       featureVectorsOfSample.push_back(featureVector);
       classOfSample.push_back( imageClasses[i]);

        printf("get feature... %f% \n",(i+1)*100.0/imagePaths.size());
        LOG_INFO_SVM_TEST("get feature... %f",(i+1)*100.0/imagePaths.size());
   }

   printf("get feature done!\n");
   LOG_INFO_SVM_TEST("get feature done!");

    // train
    printf("training...\n");
    LOG_INFO_SVM_TEST("training...");
    double time1, time2;
    time1 = getTickCount();
    svm->train(featureVectorsOfSample, ROW_SAMPLE, classOfSample);
    time2 = getTickCount();
    printf("训练时间:%f\n", (time2 - time1)*1000. / getTickFrequency());
    LOG_INFO_SVM_TEST("训练时间:%f", (time2 - time1)*1000. / getTickFrequency());
    printf("training done!\n");
    LOG_INFO_SVM_TEST("training done!");

    // save model
    svm->save(svmModelFilePath);
}

void SVMTest::Predict()
{
    // predict
    std::vector<string> testImagePaths;
    std::vector<int> testImageClasses;
    string line;
    std::ifstream testData(testDataFileList,ios::out);
    while (getline(testData, line))
    {
        if(line.empty())
            continue;

        stringstream stream(line);
        string imagePath,imageClass;
        stream>>imagePath;
        stream>>imageClass;

        testImagePaths.push_back(imagePath);
        testImageClasses.push_back(atoi(imageClass.c_str()));

    }
    testData.close();

    printf("predicting...\n");
    LOG_INFO_SVM_TEST("predicting...");

    int numberOfRight_0=0;
    int numberOfError_0=0;
    int numberOfRight_1=0;
    int numberOfError_1=0;

    std::ofstream fileOfPredictResult(predictResultFilePath,ios::out); //最后识别的结果
    double sum_Predict=0,sum_ExtractFeature=0;
    char line2[256]={0};
    for (int i = 0; i < testImagePaths.size() ; ++i)
    {
        Mat srcImage = imread(testImagePaths[i], -1);
        if(srcImage.empty()||srcImage.depth()!=CV_8U)
        {
            printf("%s srcImage.empty()||srcImage.depth()!=CV_8U!\n",testImagePaths[i].c_str());
            LOG_ERROR_SVM_TEST("%s srcImage.empty()||srcImage.depth()!=CV_8U!",testImagePaths[i].c_str());
            continue;
        }

        // extract feature
        double time1_ExtractFeature = getTickCount();
        Mat featureVectorOfTestImage;
        lbp.ComputeLBPFeatureVector_Rotation_Uniform(srcImage,Size(CELL_SIZE,CELL_SIZE),featureVectorOfTestImage);
        if(featureVectorOfTestImage.empty())
            continue;
        double time2_ExtractFeature = getTickCount();
        sum_ExtractFeature+=(time2_ExtractFeature - time1_ExtractFeature) * 1000 / getTickFrequency();

        //对测试图片进行分类并写入文件
       double time1_Predict = getTickCount();
        int predictResult = svm->predict(featureVectorOfTestImage);
        double time2_Predict = getTickCount();
        sum_Predict += (time2_Predict - time1_Predict) * 1000 / getTickFrequency();

        sprintf(line2, "%s %d\n", testImagePaths[i].c_str(), predictResult);
        fileOfPredictResult << line2;
        LOG_INFO_SVM_TEST("%s %d", testImagePaths[i].c_str(), predictResult);

        // 0
        if((testImageClasses[i]==0)&&(predictResult==0))
        {
            ++numberOfRight_0;
        }
        if((testImageClasses[i]==0)&&(predictResult!=0))
        {
            ++numberOfError_0;
        }

        // 1
        if((testImageClasses[i]==1)&&(predictResult==1))
        {
            ++numberOfRight_1;
        }
        if((testImageClasses[i]==1)&&(predictResult!=1))
        {
            ++numberOfError_1;
        }

        printf("predicting...%f%\n", 100.0*(i+1)/testImagePaths.size());
    }
    printf("predicting done!\n");
    LOG_INFO_SVM_TEST("predicting done!");

    printf("extract feature time:%f\n", sum_ExtractFeature / testImagePaths.size());
    LOG_INFO_SVM_TEST("extract feature time:%f", sum_ExtractFeature / testImagePaths.size());
    sprintf(line2, "extract feature time:%f\n", sum_ExtractFeature / testImagePaths.size());
    fileOfPredictResult << line2;

    printf("predict time:%f\n", sum_Predict / testImagePaths.size());
    LOG_INFO_SVM_TEST("predict time:%f", sum_Predict / testImagePaths.size());
    sprintf(line2, "predict time:%f\n", sum_Predict / testImagePaths.size());
    fileOfPredictResult << line2;


    // 0
    double accuracy_0=(100.0*(numberOfRight_0)) / (numberOfError_0+numberOfRight_0);
    printf("0:%f\n",accuracy_0);
    LOG_INFO_SVM_TEST("0:%f",accuracy_0);
    sprintf(line2, "0:%f\n", accuracy_0);
    fileOfPredictResult << line2;

    // 1
    double accuracy_1=(100.0*numberOfRight_1) /(numberOfError_1+numberOfRight_1);
    printf("1:%f\n",accuracy_1);
    LOG_INFO_SVM_TEST("1:%f", accuracy_1);
    sprintf(line2, "1:%f\n",accuracy_1);
    fileOfPredictResult << line2;

    // accuracy
    double accuracy_All=(100.0*(numberOfRight_1+numberOfRight_0)) /(numberOfError_0+numberOfRight_0+numberOfError_1+numberOfRight_1);
    printf("accuracy:%f\n", accuracy_All);
    LOG_INFO_SVM_TEST("accuracy:%f", accuracy_All);
    sprintf(line2, "accuracy:%f\n", accuracy_All);
    fileOfPredictResult << line2;

    fileOfPredictResult.close();

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243

程序中加入了日志,我已经在程序中注释掉了,这部分大家可以忽略。

main.cpp

#include"SVMTest.h"
int main(int argc, char *argv[])
{
    string root="/home/qq/Image2/Texture/SVMTest/";
    SVMTest svmTest(root+"Train.txt", // train filelist
                                                    root+"Test.txt", // test filelist
                                                    root+"Classifier.xml",  // classifier
                                                    root+"PredictResult.txt",  //predict result
                                                    SVM::C_SVC,  // svmType
                                                    SVM::LINEAR, // kernel
                                                    1,   // c
                                                    0,   // coef
                                                    0,   // degree
                                                    1,   // gamma
                                                    0,   // nu
                                                    0);  // p
    if(!svmTest.Initialize())
    {
        printf("initialize failed!\n");
        //LOG_ERROR_SVM_TEST("initialize failed!");
        return ;
    }

   svmTest.Train();
   svmTest.Predict();

return 0;

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

实验结果与分析

实验环境:CPU: i7-4790K,内存:16G,OS:Ubuntu 14.04,QT 5.5,OpenCV 3.1
注:很多网友说程序中的SVM报错,因为3.1中的SVM用法和2.4用法不同,所以如果你用的是2.4版本,需要更新到3.1的才可以使用.

实验中采用了2282个32X64的正样本,2278个32X64的负样本,540个测试样本
其中,正样本从下图中截取而来
这里写图片描述

负样本从下图中截取而来
这里写图片描述

正样本是草丛,负样本是路面,是我中午吃完饭散步的时候,随手拍的(-_-)

实验数据可以在这里下载

下面是我的实验结果

窗口大小 原始256维 等价模式 旋转不变等价模式
8 x 8 91.67% 93.89% 94.26%
16 x 16 95.74% 95.74% 98.52%
32 x 32 98.51% 98.52% 98.70%

可以看出,本实验中窗口大小为32x32的旋转不变的等价模式识别率最高。

注意:
程序中使用的Train.txt和Test.txt每一行的格式为:
图像的绝对路径 类别
如:
/home/qq/Image2/Texture/0/Grass_0010.jpg 0

速度测试

重构后的LBP,GetMinBinary()函数采用了查找表,实验中选取窗口大小16x16,提取一幅32X64图像的旋转不变等价模式特征为0.08ms,而没用查找表的时间为0.31ms,速度的提高还是很大的。

Last Updated: 2016-12-13 19:31:07


非常感谢您的阅读,如果您觉得这篇文章对您有帮助,欢迎扫码进行赞赏。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多