Gabor 小波变换

找了很久关于这方面的文献,介绍的都比较浅

求助领导,给了我一篇文章:

Gabor Based Kernel Partial-Least-Squares Discrimination Features for Face Recognition.pdf

看起来不是很麻烦,晚上回去实现一下,随后,上代码

// gabor.cpp
//
 
/********************************************************************
    created:    2012/10/08
    created:    08:10:2012   14:52    
    author:        SHI Juanfeng
    
    purpose:    gabor wavelet and extract gabor feature
*********************************************************************/
 
/// 转发请注明出处:http://shijuanfeng.blogbus.com/logs/222803606.html 
 
#include "stdafx.h"
 
 
#pragma once
 
 
#ifdef DEBUG
#pragma comment( lib,"opencv_contrib240d.lib" )
#pragma comment( lib,"opencv_core240d.lib" )
#pragma comment( lib,"opencv_highgui240d.lib" )
#pragma comment( lib,"opencv_imgproc240d.lib" )
#else
#pragma comment( lib,"opencv_contrib240.lib" )
#pragma comment( lib,"opencv_core240.lib" )
#pragma comment( lib,"opencv_highgui240.lib" )
#pragma comment( lib,"opencv_imgproc240.lib" )
#endif
 
#include <opencv2\opencv.hpp>
 
using namespace cv;
 
#include <vector>
 
 
/**
*    \brief GaborWavelet 的参数
*   
*                           f^2
*    ψ(f,θ,γ,η)  = ------------- exp( - (f^2*Xt^2/γ^2 + f^2*Yt^2/η^2) ) exp( j*2pai*f*Xt )
*                         pai*γ*η
*    xt = x cos θ + y sin θ,
*    yt = −x sin θ + y cos θ
*
*    ψg,h(x, y) = ψ(fg,θh,γ,η),
*      fg = fmax/(sqrtf(2))^g
*      θh = h*π/8
*    g,h由scales, orientations 决定, 例如 scales=5, orientations=8时,g={0, . . . , 4},h=h ∈ {0, . . . , 7}
*    
*      γ、η、fmax是预先设好的参数
**/
struct GaborWaveletParam
{
    float gamma;            ///< 如上公式, ,默认 sqrtf(2)
    float etah;                ///< 如上公式,默认 sqrtf(2)
    float fmax;                ///< 如上公式,默认 0.25
    int scales ;             ///< 尺度的数目
    int orientations;        ///< 方向的数目
    int width;               ///< 生成的小波窗口宽
    int height;               ///< 生成的小波窗口高
};
 
/**
*    \brief  输出固定尺度固定方向的Gabor小波
*                           f^2
*    ψ(f,θ,γ,η)  = ------------- exp( - (f^2*Xt^2/γ^2 + f^2*Yt^2/η^2) ) exp( j*2pai*f*Xt )
*                         pai*γ*η
*    xt = x cos θ + y sin θ,
*    yt = −x sin θ + y cos θ
*    \param[in] width 小波窗口宽
*    \param[in] height 小波窗口高
*    \param[in] f 参数
*    \param[in] sita  参数
*    \param[in] gamma 参数
*    \param[in] etah  参数
*    \param[in][out] KernelReal Gabor小波实部
*    \param[in][out] KernelImg Gabor小波虚部
**/
void TwoDimGaborwavelet( int width, int height, float f, float sita, float gamma, float etah, Mat &KernelReal, Mat &KernelImg  );
 
/**
*    \brief  生成多尺度、多方向的Gabor小波
*    \param[in] param 参数,详见结构体说明
*/
void GaborWaveletsMultiscalesAndMultiOrientations( GaborWaveletParam &param );
 
/**
*    \brief  提取多尺度、多方向的Gabor特征
*    1. 原图像卷积Gabor 小波 Og,h(x, y) = I(x, y) ∗ ψg,h(x, y),
*    2. 在多个尺度上进行下采样
*    3. 归一化到0均值1方差
*    4. 将各尺度变成行向量连接起来,最终的特征为scales*orientations*ImgWidth*ImgHeight/rou长的行向量
*
*    \param[in] param 参数,详见结构体说明
*    \param[in] src 原图像
*    \param[in] rou 下采样的比例
*    \param[in] gaborFeatures  求得的gabor特征
**/
void GaborFeaturesMultiscalesAndMultiOrientations( GaborWaveletParam &param, const Mat &src, float rou, vector<float> &gaborFeatures );
 
 
 
//////////////////////////////////////////////////////////////////////////
/// 实现
 
/// 输出固定尺度固定方向的Gabor小波
void TwoDimGaborwavelet( int width, int height, float f, float sita, float gamma, float etah, Mat &KernelReal, Mat &KernelImg )
{
 
    for ( int x=-width/2; x<width/2; x++)
    {
        for ( int y=-height/2; y<height/2; y++ )
        {
            float xt = x * cos(sita) + y * sin(sita);
            float yt = -x * sin(sita) + y * cos(sita);
 
            float fai = f*f / (CV_PI*gamma*etah) * exp( - f*f* ( xt*xt/(gamma*gamma) + yt*yt/(etah*etah) ) ) ;
 
            KernelReal.at<float>(x+width/2, y+height/2) = fai * cos( 2*CV_PI*f*xt);
            KernelImg.at<float>(x+width/2, y+height/2) = fai * sin( 2*CV_PI*f*xt);
        }
    }
            
}
 
/// 生成多尺度、多方向的Gabor小波
void GaborWaveletsMultiscalesAndMultiOrientations( GaborWaveletParam &param )
{
 
    int cnt = 1;
 
    Mat KernelReal = Mat::zeros( param.width, param.height, CV_32F );
    Mat KernelImg = Mat::zeros( param.width, param.height, CV_32F );
 
    for ( int g=0; g<param.scales; g++ )
    {
        for ( int h=0; h<param.orientations; h++ )
        {
            float f = param.fmax/pow( sqrtf(2.0), g );
            float sita = h * CV_PI / 8;
            TwoDimGaborwavelet( param.width, param.height, f, sita, param.gamma, param.etah, KernelReal, KernelImg );
            normalize( KernelReal, KernelReal, 0, 255, NORM_MINMAX );
 
#if 1 ///< 这里我为了测试加入了保存图像的过程,实际使用应将该部分注释,此外,我只保存了实部用以观察
            char buf[MAX_PATH] = {0};   
            itoa( cnt, buf, 10 );
            string name = "gaborWaveletKernelReal" ;
            name += buf;
            name += ".jpg";
 
            IplImage gaborWaveletImg = IplImage(KernelReal); 
            cvSaveImage( name.c_str(), &gaborWaveletImg );
            cnt++;
#endif        
        }
    }
 
}
 
 
/// 提取多尺度、多方向的Gabor特征
void GaborFeaturesMultiscalesAndMultiOrientations( GaborWaveletParam &param, const Mat &src, float rou, vector<float> &gaborFeatures )
{
 
    int cnt = 1;
 
    Mat KernelReal = Mat::zeros( param.width, param.height, CV_32F );
    Mat KernelImg = Mat::zeros( param.width, param.height, CV_32F );
    Mat faceReal;
    Mat faceImg;
    Mat faceMag = Mat::zeros( src.rows, src.cols, CV_32F );
    Mat gaborImg = Mat::zeros( src.rows/rou, src.cols/rou, CV_32F );
 
    for ( int g=0; g<param.scales; g++ )
    {
        for ( int h=0; h<param.orientations; h++ )
        {
            float f = param.fmax/pow( sqrtf(2.0), g );
            float sita = h * CV_PI / 8;
            TwoDimGaborwavelet( param.width, param.height, f, sita, param.gamma, param.etah, KernelReal, KernelImg );
 
            /// 卷积
            flip( KernelReal, KernelReal, -1 );
            filter2D( src, faceReal, -1, KernelReal, Point( -1, -1 ), 0, BORDER_REPLICATE ); 
            filter2D( src, faceImg, -1, KernelImg, Point( -1, -1 ), 0, BORDER_REPLICATE ); 
 
            /// 幅值
            faceReal = cv::Mat_<float>(faceReal);
            faceImg = cv::Mat_<float>(faceImg);
            magnitude( faceReal, faceImg, faceMag );        
 
#if 1 ///< 这里我为了测试加入了保存图像的过程,实际使用应将该部分注释调
            normalize( faceMag, faceMag, 0, 255, NORM_MINMAX );
            char buf[MAX_PATH] = {0};   
            itoa( cnt, buf, 10 );
            string name = "gaborFeaturesMag" ;
            name += buf;
            name += ".jpg";
 
            IplImage gaborWaveletImg = IplImage(faceMag); 
            cvSaveImage( name.c_str(), &gaborWaveletImg );
            cnt++;
#endif    
 
            /// 下采样到要求的尺寸
            resize( faceMag, gaborImg, gaborImg.size() );
 
            /// 归一化到0均值1方差
            Scalar m;
            Scalar stddev;
            meanStdDev( gaborImg, m, stddev ); 
 
            gaborImg = (gaborImg-m[0])/stddev[0];
 
            /// 得到特征
            for ( int i=0; i<gaborImg.rows; i++ )
            {
                for ( int j=0; j<gaborImg.cols; j++ )
                {
                    gaborFeatures.push_back( gaborImg.at<float>(i,j) );
                }
            }
        
        }
    }
 
}
 
//////////////////////////////////////////////////////////////////////////
/// 测试
int _tmain(int argc, _TCHAR* argv[])
{
    
    /// Gabor 小波
    GaborWaveletParam param;
 
    param.gamma = sqrtf(2.0);
    param.etah = sqrtf(2.0);
    param.fmax = 0.25;
    param.scales = 5; 
    param.orientations = 8;
    param. width=64; ///< 为了看的清楚,我将窗口尺寸设置较大,实际一般用不到这么大的尺寸
    param.height=64; ///< 为了看的清楚,我将窗口尺寸设置较大,实际一般用不到这么大的尺寸
    GaborWaveletsMultiscalesAndMultiOrientations( param );
 
 
    //////////////////////////////////////////////////////////////////////////
 
    /// 提取图像的Gabor特征
    /* 1. 原图像卷积Gabor 小波 Og,h(x, y) = I(x, y) ∗ ψg,h(x, y),
        2. 在多个尺度上进行下采样
        3. 归一化到0均值1方差
        4. 将各尺度变成行向量连接起来,最终的特征为scales*orientations*ImgWidth*ImgHeight/rou长的行向量
    */
 
    char name[] = "E:\\database\\CMU\\CMUPie_illum_Cropped_128x128\\04000\\27_02.jpg";
    IplImage *img = cvLoadImage( name, CV_LOAD_IMAGE_GRAYSCALE );
    Mat src( img, 0 );
 
    /// 实际使用的窗口尺寸, 若高斯核参数为sigma,窗口一般选择为6*sigma;二维时,亦然
    param. width = 6 * param.gamma; 
    param.height=6 * param.etah; 
 
    /// 下采样
    float rou = 4;
 
    /// 求得的Gabor特征,将各尺度变成行向量连接起来,长度为 scales*orientations*ImgWidth*ImgHeight/rou 
    vector<float> gaborFeatures; 
    GaborFeaturesMultiscalesAndMultiOrientations( param, src,  rou, gaborFeatures );
 
    return 0;
}
 

cpp原文件下载地址:http://www.kuaipan.cn/file/id_71521745328144392.htm

二维gabor小波是弄明白了,一维呢?公式是啥啊???继续探究

/**
*    \brief  输出一维固定尺度固定方向的Gabor小波
*                           f^2
*    ψ(f,θ,γ)  = ------------- exp( - f^2*Xt^2/γ^2 ) exp( j*pai*f*Xt )
*                         pai*γ
*    xt = x cos θ + y sin θ,
*    \param[in] width 小波窗口宽
*    \param[in] f  参数
*    \param[in] gamma 参数
*    \param[in] sita  参数
*    \param[in] gamma 参数
*    \param[in][out] KernelReal Gabor小波实部
*    \param[in][out] KernelImg Gabor小波虚部
**/
void GaborWavelet( int width, float f, float gamma, float sita, Mat &KernelReal, Mat &KernelImg  )
{
    for ( int x=-width/2; x<width/2; x++)
    {
        float xt = x * cos(sita);
 
        float fai = f*f / ( sqrtf(CV_PI)*gamma) * exp( - f*f*xt*xt/(gamma*gamma) ) ;
 
        KernelReal.at<float>(x+width/2, 0 ) = fai * cos( CV_PI*f*xt);
        KernelImg.at<float>(x+width/2,0 ) = fai * sin( CV_PI*f*xt);
        
    }
}
 
int _tmain(int argc, _TCHAR* argv[])
{
    int width = 4;
    Mat KernelReal = Mat::zeros( width, 1, CV_32F );
    Mat KernelImg = Mat::zeros( width, 1, CV_32F );
    GaborWavelet( width, 0.25, 1, 6./CV_PI, KernelReal, KernelImg  );
 
    /// 归一化到sqrtf(2)均值1方差
    Scalar m;
    Scalar stddev;
    meanStdDev( KernelReal, m, stddev ); 
    KernelReal = sqrtf(2.) * (KernelReal-m[0])/stddev[0];
 
    meanStdDev( KernelImg, m, stddev ); 
    KernelImg = sqrtf(2.) * (KernelImg-m[0])/stddev[0];
 
 
    /// 幅值
    Mat KernelMag =  Mat::zeros( width, 1, CV_32F );
    KernelReal = cv::Mat_<float>(KernelReal);
    KernelImg = cv::Mat_<float>(KernelImg);
    magnitude( KernelReal, KernelImg, KernelMag );    
 
    for ( int i=0; i<width; i++ )
    {
        cout << KernelReal.at<float>(i,0) << "    ";
    }
    cout << endl; 
 
    for ( int i=0; i<width; i++ )
    {
        cout << KernelImg.at<float>(i,0) << "    ";
    }
    cout << endl;
 
    for ( int i=0; i<width; i++ )
    {
        cout << KernelMag.at<float>(i,0) << "    ";
    }
    cout << endl;
 
    return 0;

}

 

源自作者:http://shijuanfeng.blogbus.com/logs/222803606.html

你可能感兴趣的:(Gabor 小波变换)