VQ.cpp
上传用户:goak128
上传日期:2013-07-17
资源大小:155k
文件大小:9k
源码类别:

控制台编程

开发平台:

C/C++

  1. #include "StdAfx.h"
  2. #include ".vq.h"
  3. #include <math.h>
  4. //////////////////////////////////////////////////////////////////////////
  5. // 构造函数
  6. // 
  7. // 创建人: 陈文凯
  8. // 创建日期: 2005-06-07
  9. // 修改人:
  10. // 修改日期:
  11. CVQ::CVQ(void)
  12. {
  13. }
  14. //////////////////////////////////////////////////////////////////////////
  15. // 析造函数
  16. // 
  17. // 创建人: 陈文凯
  18. // 创建日期: 2005-06-07
  19. // 修改人:
  20. // 修改日期:
  21. CVQ::~CVQ(void)
  22. {
  23. }
  24. ////////////////////////////////////////////////////////////////////////////
  25. //// 采用LGB算法进行VQ
  26. //// 
  27. //// 创建人: 陈文凯
  28. //// 创建日期: 2005-06-07
  29. //// 修改人:
  30. //// 修改日期:
  31. //void CVQ::LGB( 
  32. //   const double* pInVector, // 输入样本序列
  33. //   unsigned int nInLen, // 输入样本序列长度
  34. //   const double* pInCodeBook, // 输入码本,可为空
  35. //   double* pOutCodeBook, // 输出码本
  36. //   unsigned int nCodeNums, // 码本长度
  37. //   unsigned int nMaxReapt, // 最大迭代次数
  38. //   double fMinChange, // 畸变改进阈值
  39. //   double fInitDistortion // 初始畸变
  40. //   )
  41. //{
  42. // // 当前总畸变
  43. // double fCurDistortion = fInitDistortion;
  44. // // 调用LGBRepeat返回的总畸变
  45. // double fRetDistortion = 0;
  46. // // 当前迭代次数
  47. // unsigned int nCurRepeat = 0;
  48. // // 当前畸变改进量
  49. // double fCurChange = fInitDistortion;
  50. //
  51. // // 若初始码本为空,则用输入序列的前nCodeNums个样本为初始码本
  52. // if (pInCodeBook == NULL)
  53. // {
  54. // memcpy(pOutCodeBook, pInVector, sizeof(double) * nCodeNums);
  55. // }
  56. //
  57. // // 调用LGBRepeat进行迭代
  58. // while (nCurRepeat < nMaxReapt && fMinChange < fCurChange)
  59. // {
  60. // fRetDistortion = CVQ::LGBRepeat(pInVector, nInLen, pOutCodeBook, nCodeNums);
  61. //
  62. // // 计算当前畸变改进量
  63. // fCurChange = abs(fCurDistortion - fRetDistortion) / fCurDistortion;
  64. // fCurDistortion = fRetDistortion;
  65. // }
  66. //}
  67. //
  68. ////////////////////////////////////////////////////////////////////////////
  69. //// 进行LGB算法迭代,输出总畸变
  70. //// 
  71. //// 创建人: 陈文凯
  72. //// 创建日期: 2005-06-07
  73. //// 修改人:
  74. //// 修改日期:
  75. //double CVQ::LGBRepeat( 
  76. // const double* pInVector, // 输入样本序列
  77. // unsigned int nInLen, // 输入样本序列长度
  78. // double* pCodeBook, // 输入/出码本
  79. // unsigned int nCodeNums // 码本长度
  80. // )
  81. //{
  82. // // 聚类时每个码矢代表的样本数
  83. // unsigned int pnSampleNums[nCodeNums];
  84. // // 聚类时进行样本叠加值
  85. // double pfSampleSums[nCodeNums];
  86. // // 保存总畸变
  87. // double fDistortion = 0;
  88. // // 保存相邻的码矢下标
  89. // unsigned int nNearCode = 0;
  90. // // 保存样本与码矢距离
  91. // double fDistance = 0;
  92. //
  93. // // 初始化聚类时每个码矢代表的样本数
  94. // memset(pnSampleNums, 0, sizeof(unsigned int) * nCodeNums);
  95. // // 初始化聚类时进行样本叠加值
  96. // memset(pfSampleSums, 0, sizeof(double) * nCodeNums);
  97. //
  98. // // 按照输入码本对输入样本序列进行分段
  99. // for (int i = 0; i < nInLen; i++)
  100. // {
  101. // fDistance = CVQ_MAXIMUN;
  102. //
  103. // for(int j = 0; j < nCodeNums; j++)
  104. // {
  105. // if (abs(pInVector[i] - pCodeBook[j]) < fDistance)
  106. // {
  107. // fDistance = abs(pInVector[i] - pCodeBook[j]);
  108. //
  109. // nNearCode = j;
  110. // }
  111. // }
  112. //
  113. // pfSampleSums[nNearCode] += pInVector[i];
  114. // pnSampleNums[nNearCode] ++;
  115. // }
  116. //
  117. // // 计算总畸变
  118. // for (int i = 0; i < nCodeNums; i++)
  119. // {
  120. // for (int j = 0; j < pnSamplesNums)
  121. // }
  122. //
  123. // // 计算码本
  124. //
  125. // return fDistortion;
  126. //}
  127. //////////////////////////////////////////////////////////////////////////
  128. // 对输入样本进行简单聚类
  129. // 先对输入样本进行分段,然后简单的求每个分段的均值作为码本
  130. // 产生的码本与时间t相关
  131. //
  132. // 创建人: 陈文凯
  133. // 创建日期: 2005-06-07
  134. // 修改人:
  135. // 修改日期:
  136. void CVQ::EasyCluster(
  137.   const double* pInVector, // 输入样本序列
  138.   unsigned int nInLen, // 输入样本序列长度
  139.   double* pCodeBook, // 输入/出码本
  140.   unsigned int nCodeNums // 码本长度
  141.   )
  142. {
  143. unsigned int nSegLen = nInLen / nCodeNums;
  144. unsigned int nOffSet = 0;
  145. // 初始化码本
  146. memset(pCodeBook, 0, sizeof(double) * nCodeNums);
  147. for (unsigned int i = 0; i < nCodeNums; i++)
  148. {
  149. nOffSet = i * nSegLen;
  150. for (unsigned int j = 0; j < nSegLen; j++)
  151. {
  152. pCodeBook[i] += pInVector[nOffSet + j];
  153. }
  154. // 对码矢求均值
  155. pCodeBook[i] /= nSegLen;
  156. }
  157. }
  158. //////////////////////////////////////////////////////////////////////////
  159. // 实现K均值聚类
  160. //
  161. // 创建人: 陈文凯
  162. // 创建日期: 2005-06-07
  163. // 修改人:
  164. // 修改日期:
  165. void CVQ::KMeansCluster(
  166. const double* pInVector, // 输入样本序列
  167. unsigned int nInLen, // 输入样本序列长度
  168. double* pCodeBook, // 输出码本
  169. unsigned int nCodeNums // 码本长度
  170. )
  171. {
  172. // pInVector(i)是否属于pCodeBook(j)
  173. unsigned int* pFlag = NULL;
  174. // 迭代中使用到的码本
  175. double* pNewCodeBook = NULL;
  176. // 循环变量
  177. unsigned int i = 0;
  178. unsigned int j = 0;
  179. // 迭代返回的畸变
  180. double fDistortion = 0;
  181. // 对码本进行升序排序
  182. double fMinCode = 0;
  183. unsigned int nMinIndex = 0;
  184. if (pInVector != NULL && pCodeBook != NULL)
  185. {
  186. // 分配化标志矩阵
  187. pFlag = new unsigned int[nCodeNums * nInLen];
  188. // 分配迭代码本
  189. pNewCodeBook = new double[nCodeNums];
  190. // 使用EasyCluster设定初始码本
  191. CVQ::EasyCluster(pInVector, nInLen, pCodeBook, nCodeNums);
  192. for (i = 0; i < nCodeNums; i++)
  193. {
  194. TRACE("%fn", pCodeBook[i]);
  195. }
  196. // 迭代聚类
  197. fDistortion = 1;
  198. while (fDistortion > 0)
  199. {
  200. fDistortion = CVQ::KMeansClusterRepeat(
  201. pInVector, nInLen, pCodeBook, nCodeNums, pFlag, pNewCodeBook);
  202. // 拷贝新码本
  203. memcpy(pCodeBook, pNewCodeBook, sizeof(double) * nCodeNums);
  204. for (i = 0; i < nCodeNums; i++)
  205. {
  206. TRACE("%fn", pCodeBook[i]);
  207. }
  208. TRACE("#####################n");
  209. }
  210. // 对码本进行升序排序
  211. for (i = 0; i < nCodeNums; i++)
  212. {
  213. fMinCode = pCodeBook[i];
  214. nMinIndex = i;
  215. for (j = i + 1; j < nCodeNums; j++)
  216. {
  217. if (pCodeBook[j] < fMinCode)
  218. {
  219. fMinCode =  pCodeBook[j];
  220. nMinIndex = j;
  221. }
  222. }
  223. pCodeBook[nMinIndex] = pCodeBook[i];
  224. pCodeBook[i] = fMinCode;
  225. }
  226. // 释放所占资源
  227. delete[] pNewCodeBook;
  228. delete[] pFlag;
  229. }
  230. }
  231. //////////////////////////////////////////////////////////////////////////
  232. // 实现K均值聚类的迭代过程, 输出码书的畸变程度
  233. //
  234. // 创建人: 陈文凯
  235. // 创建日期: 2005-06-12
  236. // 修改人:
  237. // 修改日期:
  238. double CVQ::KMeansClusterRepeat(
  239. const double* pInVector, // 输入样本序列
  240. unsigned int nInLen, // 输入样本序列长度
  241. double* pCodeBook, // 输入码本
  242. unsigned int nCodeNums, // 码本长度
  243. unsigned int* pFlag, // 用于分类的数组,再KMeansCluster中分配
  244. double* pNewCodeBook // 输出新码本
  245. )
  246. {
  247. // 畸变
  248. double fDistortion = 0;
  249. // 样本和码本的最小距离
  250. double fMinDis = 0;
  251. // 计算样本和码本的距离
  252. double fDis = 0;
  253. // 最小距离对应的码本下标
  254. unsigned int nIndex = 0;
  255. // 码本包含样本数
  256. unsigned int nSamplesCount = 0;
  257. // 码本中样本累积
  258. double fSamplesSum = 0;
  259. // 循环变量
  260. unsigned int i = 0;
  261. unsigned int j = 0;
  262. if (pInVector != NULL)
  263. {
  264. // 初始化输出新码本
  265. memset(pNewCodeBook, 0, sizeof(double) * nCodeNums);
  266. // 初始化标志矩阵
  267. memset(pFlag, 0, sizeof(unsigned int) * nCodeNums * nInLen);
  268. // 聚类
  269. for (i = 0; i < nInLen; i++)
  270. {
  271. // 初始最小值
  272. fMinDis = abs(pInVector[i] - pCodeBook[0]);
  273. nIndex = 0;
  274. for (j = 0; j < nCodeNums; j++)
  275. {
  276. fDis = abs(pInVector[i] - pCodeBook[j]);
  277. if (fDis < fMinDis)
  278. {
  279. fMinDis = fDis;
  280. nIndex = j;
  281. }
  282. }
  283. // 设定pInVector[i]属于中心pCodeBook[nIndex];
  284. pFlag[nIndex * nInLen + i] = 1;
  285. }
  286. // 计算新码本
  287. for (i = 0; i < nCodeNums; i++)
  288. {
  289. fSamplesSum = 0;
  290. nSamplesCount = 0;
  291. for (j = 0; j < nInLen; j++)
  292. {
  293. if (pFlag[i * nInLen + j] == 1)
  294. {
  295. nSamplesCount++;
  296. fSamplesSum += pInVector[j];
  297. }
  298. }
  299. // 当堆大小为0时,对应码矢为0
  300. pNewCodeBook[i] = 
  301. (nSamplesCount == 0 ? 0 : (fSamplesSum / nSamplesCount));
  302. fDistortion += abs(pCodeBook[i] - pNewCodeBook[i]);
  303. }
  304. // 计算畸变
  305. fDistortion /= nCodeNums;
  306. }
  307. return fDistortion;
  308. }
  309. //////////////////////////////////////////////////////////////////////////
  310. // 对输入码本,按照标准码本进行分类
  311. //
  312. // 创建人: 陈文凯
  313. // 创建日期: 2005-06-12
  314. // 修改人:
  315. // 修改日期:
  316. void CVQ::Classify(
  317.    const double* pInCodeBook, // 输入码本
  318.    unsigned int nInNums, // 输入码本中码字数量
  319.    const double* pCodeBook, // 模板码本
  320.    unsigned int nCodeNums, // 模板码本中码字数量
  321.    unsigned int* pKinds // 输入码本中的码字对应的模板码本中码字的下标
  322.    )
  323. {
  324. // 码本的最小距离
  325. double fMinDis = 0;
  326. // 最小距离对应的模板码字的下标
  327. unsigned int nMinIndex = 0;
  328. // 计算码本距离
  329. double fDis = 0;
  330. if (pInCodeBook != NULL && pCodeBook != NULL)
  331. {
  332. // 初始化码字下标
  333. memset(pKinds, 0, sizeof(unsigned int) * nInNums);
  334. for (unsigned int i = 0; i < nInNums; i++)
  335. {
  336. // 初始化最小距离
  337. fMinDis = abs(pInCodeBook[i] - pCodeBook[0]);
  338. nMinIndex = 0;
  339. // 计算最小距离
  340. for (unsigned int j = 0; j < nCodeNums; j++)
  341. {
  342. fDis = abs(pInCodeBook[i] - pCodeBook[j]);
  343. if (fDis < fMinDis)
  344. {
  345. fMinDis = fDis;
  346. nMinIndex = j;
  347. }
  348. }
  349. // 保存码字下标
  350. pKinds[i] = nMinIndex;
  351. TRACE("pKinds[%d]: %dn", i, nMinIndex);
  352. }
  353. }
  354. }
  355. //////////////////////////////////////////////////////////////////////////
  356. // 计算两个码本的欧式距离
  357. double CVQ::GetDistance( const double* pCode1, const double* pCode2, unsigned int nCodeNums )
  358. {
  359. double fSum = 0;
  360. for (unsigned int i = 0; i < nCodeNums; i++)
  361. {
  362. fSum += (pCode1[i] - pCode2[i]) * (pCode1[i] - pCode2[i]);
  363. }
  364. return sqrt(fSum);
  365. }