VQ.cpp
上传用户:goak128
上传日期:2013-07-17
资源大小:155k
文件大小:9k
- #include "StdAfx.h"
- #include ".vq.h"
- #include <math.h>
- //////////////////////////////////////////////////////////////////////////
- // 构造函数
- //
- // 创建人: 陈文凯
- // 创建日期: 2005-06-07
- // 修改人:
- // 修改日期:
- CVQ::CVQ(void)
- {
- }
- //////////////////////////////////////////////////////////////////////////
- // 析造函数
- //
- // 创建人: 陈文凯
- // 创建日期: 2005-06-07
- // 修改人:
- // 修改日期:
- CVQ::~CVQ(void)
- {
- }
- ////////////////////////////////////////////////////////////////////////////
- //// 采用LGB算法进行VQ
- ////
- //// 创建人: 陈文凯
- //// 创建日期: 2005-06-07
- //// 修改人:
- //// 修改日期:
- //void CVQ::LGB(
- // const double* pInVector, // 输入样本序列
- // unsigned int nInLen, // 输入样本序列长度
- // const double* pInCodeBook, // 输入码本,可为空
- // double* pOutCodeBook, // 输出码本
- // unsigned int nCodeNums, // 码本长度
- // unsigned int nMaxReapt, // 最大迭代次数
- // double fMinChange, // 畸变改进阈值
- // double fInitDistortion // 初始畸变
- // )
- //{
- // // 当前总畸变
- // double fCurDistortion = fInitDistortion;
- // // 调用LGBRepeat返回的总畸变
- // double fRetDistortion = 0;
- // // 当前迭代次数
- // unsigned int nCurRepeat = 0;
- // // 当前畸变改进量
- // double fCurChange = fInitDistortion;
- //
- // // 若初始码本为空,则用输入序列的前nCodeNums个样本为初始码本
- // if (pInCodeBook == NULL)
- // {
- // memcpy(pOutCodeBook, pInVector, sizeof(double) * nCodeNums);
- // }
- //
- // // 调用LGBRepeat进行迭代
- // while (nCurRepeat < nMaxReapt && fMinChange < fCurChange)
- // {
- // fRetDistortion = CVQ::LGBRepeat(pInVector, nInLen, pOutCodeBook, nCodeNums);
- //
- // // 计算当前畸变改进量
- // fCurChange = abs(fCurDistortion - fRetDistortion) / fCurDistortion;
- // fCurDistortion = fRetDistortion;
- // }
- //}
- //
- ////////////////////////////////////////////////////////////////////////////
- //// 进行LGB算法迭代,输出总畸变
- ////
- //// 创建人: 陈文凯
- //// 创建日期: 2005-06-07
- //// 修改人:
- //// 修改日期:
- //double CVQ::LGBRepeat(
- // const double* pInVector, // 输入样本序列
- // unsigned int nInLen, // 输入样本序列长度
- // double* pCodeBook, // 输入/出码本
- // unsigned int nCodeNums // 码本长度
- // )
- //{
- // // 聚类时每个码矢代表的样本数
- // unsigned int pnSampleNums[nCodeNums];
- // // 聚类时进行样本叠加值
- // double pfSampleSums[nCodeNums];
- // // 保存总畸变
- // double fDistortion = 0;
- // // 保存相邻的码矢下标
- // unsigned int nNearCode = 0;
- // // 保存样本与码矢距离
- // double fDistance = 0;
- //
- // // 初始化聚类时每个码矢代表的样本数
- // memset(pnSampleNums, 0, sizeof(unsigned int) * nCodeNums);
- // // 初始化聚类时进行样本叠加值
- // memset(pfSampleSums, 0, sizeof(double) * nCodeNums);
- //
- // // 按照输入码本对输入样本序列进行分段
- // for (int i = 0; i < nInLen; i++)
- // {
- // fDistance = CVQ_MAXIMUN;
- //
- // for(int j = 0; j < nCodeNums; j++)
- // {
- // if (abs(pInVector[i] - pCodeBook[j]) < fDistance)
- // {
- // fDistance = abs(pInVector[i] - pCodeBook[j]);
- //
- // nNearCode = j;
- // }
- // }
- //
- // pfSampleSums[nNearCode] += pInVector[i];
- // pnSampleNums[nNearCode] ++;
- // }
- //
- // // 计算总畸变
- // for (int i = 0; i < nCodeNums; i++)
- // {
- // for (int j = 0; j < pnSamplesNums)
- // }
- //
- // // 计算码本
- //
- // return fDistortion;
- //}
- //////////////////////////////////////////////////////////////////////////
- // 对输入样本进行简单聚类
- // 先对输入样本进行分段,然后简单的求每个分段的均值作为码本
- // 产生的码本与时间t相关
- //
- // 创建人: 陈文凯
- // 创建日期: 2005-06-07
- // 修改人:
- // 修改日期:
- void CVQ::EasyCluster(
- const double* pInVector, // 输入样本序列
- unsigned int nInLen, // 输入样本序列长度
- double* pCodeBook, // 输入/出码本
- unsigned int nCodeNums // 码本长度
- )
- {
- unsigned int nSegLen = nInLen / nCodeNums;
- unsigned int nOffSet = 0;
- // 初始化码本
- memset(pCodeBook, 0, sizeof(double) * nCodeNums);
- for (unsigned int i = 0; i < nCodeNums; i++)
- {
- nOffSet = i * nSegLen;
- for (unsigned int j = 0; j < nSegLen; j++)
- {
- pCodeBook[i] += pInVector[nOffSet + j];
- }
- // 对码矢求均值
- pCodeBook[i] /= nSegLen;
- }
- }
- //////////////////////////////////////////////////////////////////////////
- // 实现K均值聚类
- //
- // 创建人: 陈文凯
- // 创建日期: 2005-06-07
- // 修改人:
- // 修改日期:
- void CVQ::KMeansCluster(
- const double* pInVector, // 输入样本序列
- unsigned int nInLen, // 输入样本序列长度
- double* pCodeBook, // 输出码本
- unsigned int nCodeNums // 码本长度
- )
- {
- // pInVector(i)是否属于pCodeBook(j)
- unsigned int* pFlag = NULL;
- // 迭代中使用到的码本
- double* pNewCodeBook = NULL;
- // 循环变量
- unsigned int i = 0;
- unsigned int j = 0;
- // 迭代返回的畸变
- double fDistortion = 0;
- // 对码本进行升序排序
- double fMinCode = 0;
- unsigned int nMinIndex = 0;
- if (pInVector != NULL && pCodeBook != NULL)
- {
- // 分配化标志矩阵
- pFlag = new unsigned int[nCodeNums * nInLen];
- // 分配迭代码本
- pNewCodeBook = new double[nCodeNums];
-
- // 使用EasyCluster设定初始码本
- CVQ::EasyCluster(pInVector, nInLen, pCodeBook, nCodeNums);
- for (i = 0; i < nCodeNums; i++)
- {
- TRACE("%fn", pCodeBook[i]);
- }
- // 迭代聚类
- fDistortion = 1;
- while (fDistortion > 0)
- {
- fDistortion = CVQ::KMeansClusterRepeat(
- pInVector, nInLen, pCodeBook, nCodeNums, pFlag, pNewCodeBook);
- // 拷贝新码本
- memcpy(pCodeBook, pNewCodeBook, sizeof(double) * nCodeNums);
- for (i = 0; i < nCodeNums; i++)
- {
- TRACE("%fn", pCodeBook[i]);
- }
- TRACE("#####################n");
- }
- // 对码本进行升序排序
- for (i = 0; i < nCodeNums; i++)
- {
- fMinCode = pCodeBook[i];
- nMinIndex = i;
- for (j = i + 1; j < nCodeNums; j++)
- {
- if (pCodeBook[j] < fMinCode)
- {
- fMinCode = pCodeBook[j];
- nMinIndex = j;
- }
- }
- pCodeBook[nMinIndex] = pCodeBook[i];
- pCodeBook[i] = fMinCode;
- }
- // 释放所占资源
- delete[] pNewCodeBook;
- delete[] pFlag;
- }
- }
- //////////////////////////////////////////////////////////////////////////
- // 实现K均值聚类的迭代过程, 输出码书的畸变程度
- //
- // 创建人: 陈文凯
- // 创建日期: 2005-06-12
- // 修改人:
- // 修改日期:
- double CVQ::KMeansClusterRepeat(
- const double* pInVector, // 输入样本序列
- unsigned int nInLen, // 输入样本序列长度
- double* pCodeBook, // 输入码本
- unsigned int nCodeNums, // 码本长度
- unsigned int* pFlag, // 用于分类的数组,再KMeansCluster中分配
- double* pNewCodeBook // 输出新码本
- )
- {
- // 畸变
- double fDistortion = 0;
- // 样本和码本的最小距离
- double fMinDis = 0;
- // 计算样本和码本的距离
- double fDis = 0;
- // 最小距离对应的码本下标
- unsigned int nIndex = 0;
- // 码本包含样本数
- unsigned int nSamplesCount = 0;
- // 码本中样本累积
- double fSamplesSum = 0;
- // 循环变量
- unsigned int i = 0;
- unsigned int j = 0;
- if (pInVector != NULL)
- {
- // 初始化输出新码本
- memset(pNewCodeBook, 0, sizeof(double) * nCodeNums);
- // 初始化标志矩阵
- memset(pFlag, 0, sizeof(unsigned int) * nCodeNums * nInLen);
- // 聚类
- for (i = 0; i < nInLen; i++)
- {
- // 初始最小值
- fMinDis = abs(pInVector[i] - pCodeBook[0]);
- nIndex = 0;
- for (j = 0; j < nCodeNums; j++)
- {
- fDis = abs(pInVector[i] - pCodeBook[j]);
- if (fDis < fMinDis)
- {
- fMinDis = fDis;
- nIndex = j;
- }
- }
- // 设定pInVector[i]属于中心pCodeBook[nIndex];
- pFlag[nIndex * nInLen + i] = 1;
- }
- // 计算新码本
- for (i = 0; i < nCodeNums; i++)
- {
- fSamplesSum = 0;
- nSamplesCount = 0;
- for (j = 0; j < nInLen; j++)
- {
- if (pFlag[i * nInLen + j] == 1)
- {
- nSamplesCount++;
- fSamplesSum += pInVector[j];
- }
- }
- // 当堆大小为0时,对应码矢为0
- pNewCodeBook[i] =
- (nSamplesCount == 0 ? 0 : (fSamplesSum / nSamplesCount));
- fDistortion += abs(pCodeBook[i] - pNewCodeBook[i]);
- }
- // 计算畸变
- fDistortion /= nCodeNums;
- }
- return fDistortion;
- }
- //////////////////////////////////////////////////////////////////////////
- // 对输入码本,按照标准码本进行分类
- //
- // 创建人: 陈文凯
- // 创建日期: 2005-06-12
- // 修改人:
- // 修改日期:
- void CVQ::Classify(
- const double* pInCodeBook, // 输入码本
- unsigned int nInNums, // 输入码本中码字数量
- const double* pCodeBook, // 模板码本
- unsigned int nCodeNums, // 模板码本中码字数量
- unsigned int* pKinds // 输入码本中的码字对应的模板码本中码字的下标
- )
- {
- // 码本的最小距离
- double fMinDis = 0;
- // 最小距离对应的模板码字的下标
- unsigned int nMinIndex = 0;
- // 计算码本距离
- double fDis = 0;
- if (pInCodeBook != NULL && pCodeBook != NULL)
- {
- // 初始化码字下标
- memset(pKinds, 0, sizeof(unsigned int) * nInNums);
- for (unsigned int i = 0; i < nInNums; i++)
- {
- // 初始化最小距离
- fMinDis = abs(pInCodeBook[i] - pCodeBook[0]);
- nMinIndex = 0;
- // 计算最小距离
- for (unsigned int j = 0; j < nCodeNums; j++)
- {
- fDis = abs(pInCodeBook[i] - pCodeBook[j]);
- if (fDis < fMinDis)
- {
- fMinDis = fDis;
- nMinIndex = j;
- }
- }
- // 保存码字下标
- pKinds[i] = nMinIndex;
- TRACE("pKinds[%d]: %dn", i, nMinIndex);
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////
- // 计算两个码本的欧式距离
- double CVQ::GetDistance( const double* pCode1, const double* pCode2, unsigned int nCodeNums )
- {
- double fSum = 0;
- for (unsigned int i = 0; i < nCodeNums; i++)
- {
- fSum += (pCode1[i] - pCode2[i]) * (pCode1[i] - pCode2[i]);
- }
- return sqrt(fSum);
- }